Railway Operation Simulator  v2.8.0
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <Clipbrd.hpp> //for selection clipboard functions at v2.8.0
38 #include <fstream>
39 #include <sstream> //for clipboard functions at v2.8.0
40 #include <vector>
41 #include <vcl.h>
42 #include <stdio.h>
43 #include <algorithm> //for sort
44 
45 #pragma hdrstop
46 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
47 // They aren't all needed in each case but being together and identical they speed
48 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
49 // conjunction with 'use pre-compiled headers' in the project compiler options.
50 
51 #include "InterfaceUnit.h"
52 #include "GraphicUnit.h"
53 #include "DisplayUnit.h"
54 #include "TextUnit.h"
55 #include "TrainUnit.h"
56 #include "Utilities.h"
57 #include "TrackUnit.h"
58 #include "AboutUnit.h"
59 #include <fstream>
60 #include <dirent.h>
61 #include <Filectrl.hpp> //to check whether directories exist
62 
63 // ---------------------------------------------------------------------------
64 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
65 #pragma package(smart_init)
66 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
67 #pragma resource "*.dfm"
68 
70 
71 // Folder Names
72 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
73 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
74 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
75 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
76 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
77 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
78 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
79 
80 // ---------------------------------------------------------------------------
81 
82 __fastcall TInterface::TInterface(TComponent* Owner) : TForm(Owner)
83 {
84  // constructor
85  try
86  {
87  Screen->Cursor = TCursor(-11); // Hourglass
88  DirOpenError = false;
89  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
90  // initial setup
91  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
92  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
94  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
95  // development stages (don't show on published versions)
96 
97  // check for presence of directories, creation failure probably indicates that the
98  // working folder is read-only
99  CurDir = GetCurrentDir();
100  if(!DirectoryExists(RAILWAY_DIR_NAME))
101  {
102  if(!CreateDir(RAILWAY_DIR_NAME))
103  {
104  DirOpenError = true;
105  }
106  }
107  if(!DirectoryExists(TIMETABLE_DIR_NAME))
108  {
109  if(!CreateDir(TIMETABLE_DIR_NAME))
110  {
111  DirOpenError = true;
112  }
113  }
114  if(!DirectoryExists(PERFLOG_DIR_NAME))
115  {
116  if(!CreateDir(PERFLOG_DIR_NAME))
117  {
118  DirOpenError = true;
119  }
120  }
121  if(!DirectoryExists(SESSION_DIR_NAME))
122  {
123  if(!CreateDir(SESSION_DIR_NAME))
124  {
125  DirOpenError = true;
126  }
127  }
128  if(!DirectoryExists(IMAGE_DIR_NAME))
129  {
130  if(!CreateDir(IMAGE_DIR_NAME))
131  {
132  DirOpenError = true;
133  }
134  }
135  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
136  {
137  if(!CreateDir(FORMATTEDTT_DIR_NAME))
138  {
139  DirOpenError = true;
140  }
141  }
142  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
143  {
144  if(!CreateDir(USERGRAPHICS_DIR_NAME))
145  {
146  DirOpenError = true;
147  }
148  }
149  if(DirOpenError)
150  {
151  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
153  "program operation may be restricted");
154  }
155  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
156 
157  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
158  PopupMenu->AutoHotkeys = maManual; // as above
159 
160  Utilities = new TUtilities;
161  RailGraphics = new TRailGraphics();
162 
163  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
164  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
165  MainScreen->Width = DispW * 16;
166  MainScreen->Height = DispH * 16;
167 
170  Utilities->ScreenElementWidth = DispW;
172  HiddenScreen = new TImage(Interface);
173  HiddenScreen->Width = MainScreen->Width;
174  HiddenScreen->Height = MainScreen->Height;
178  Track = new TTrack;
179  AllRoutes = new TAllRoutes;
184  SelectBitmap = new Graphics::TBitmap;
185  SelectBitmap->PixelFormat = pf8bit;
186  SelectBitmap->Transparent = true;
191  LengthWarningSentFlag = false;
192  PasteWarningSentFlag = false; // added at v2.6.0
193  FillSelectionMessageSentFlag = false; // added at v2.6.0
194  LCManualLowerBarriersMessageSent = false; // added at v2.6.0
195  RecoverClipboardMessageSent = false; // added at v2.8.0
196 
197  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
198  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
199  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
200  ResetAll(0);
201 
202  TempTTFileName = "";
203 
208 
209  RouteFlashDuration = 0.0;
210  PointsFlashDuration = 0.0;
211 
212  FloatingLabel->Color = clB4G5R5;
213  TrackElementPanel->Color = clB5G5R4;
214  InfoPanel->Color = clB4G5R5;
215 
216  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME; // not changeable
217 
218  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
219  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
220  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
221  SigsOnLeftImage1->Transparent = true;
222  SigsOnLeftImage2->Transparent = true;
223  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
224  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
225  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
226  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
227  SigsOnRightImage1->Transparent = true;
228  SigsOnRightImage2->Transparent = true;
229  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
230  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
231 
232  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME; // default locations if not updated from Config.txt
233  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
234  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
235  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
236  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
237 
238  std::ifstream ConfigFile((CurDir + "\\Config.txt").c_str()); // added at v2.6.0 to set save & load directories for railways, timetables & session & to
239  if(ConfigFile.fail()) // no Config file //replace Signal.hnd, Background.col and GNU
240  {
241  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
242  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
243  SigsOnLeftImage1->Visible = true;
244  SigsOnLeftImage2->Visible = true;
245  SigsOnRightImage1->Visible = false;
246  SigsOnRightImage2->Visible = false;
247  ShowMessage(
248  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. " "It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; "
249  "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - " "you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>."
250  );
251  }
252  else
253  {
254  AnsiString ConfigStr = "";
255  do
256  {
257  Utilities->CheckAndReadFileString(ConfigFile, ConfigStr);
258  if(ConfigFile.eof())
259  {
260  break;
261  }
262  AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
263  if(ConfigStr.SubString(1, 8) == "Signals=")
264  {
265  if(ConfigValue == "right")
266  {
267  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program, toggles Utilities->RHSignalFlag
268  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
270  {
272  }
273  else
274  {
276  }
277  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
278  SigsOnLeftImage1->Visible = false;
279  SigsOnLeftImage2->Visible = false;
280  SigsOnRightImage1->Visible = true;
281  SigsOnRightImage2->Visible = true;
282  }
283  else
284  {
285  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
286  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
287  SigsOnLeftImage1->Visible = true;
288  SigsOnLeftImage2->Visible = true;
289  SigsOnRightImage1->Visible = false;
290  SigsOnRightImage2->Visible = false;
291  }
292  }
293  if(ConfigStr.SubString(1, 8) == "BgndCol=")
294  {
295  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
296  Utilities->clTransparent = clB0G0R0; // default black background;
297  if(ConfigValue == "white")
298  {
299  Utilities->clTransparent = TColor(0xFFFFFF);
300  }
301  else if(ConfigValue == "blue")
302  {
303  Utilities->clTransparent = TColor(0x330000);
304  }
305  }
306  if(ConfigStr.SubString(1, 8) == "RLYLocn=")
307  {
308  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
309  {
310  SaveRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
311  LoadRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
312  }
313  }
314  else if(ConfigStr.SubString(1, 8) == "TTBLocn=")
315  {
316  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
317  {
318  TimetableDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
319  SaveTTDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
320  }
321  }
322  else if(ConfigStr.SubString(1, 8) == "SSNLocn=")
323  {
324  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
325  {
326  LoadSessionDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
327  }
328  }
329  }
330  while(!ConfigFile.eof());
331  ConfigFile.close();
332  }
333  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
334  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
335  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
336  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
337  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
338  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
339  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
340  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
341  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
342  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
343  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
344  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
345  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
346  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
347  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
348  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
349  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
350  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
351  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
352  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
353  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
354  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
355  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
356  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
357  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
358  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
359  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
360  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
361  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
362  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
363  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
364  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
365  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
366  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
367  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
368  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
369  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
370  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
371  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
372  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
373  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
374  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
375  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
376  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
377  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
378  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
379  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
380  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
381  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
382  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
383  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
384  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
385  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
386  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
387  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
388  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
389  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
390  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
391  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
392  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
393  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
394  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
395  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
396  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
397  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
398  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
399  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
400  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
401  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
402  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
403  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
404  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
405  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
406  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
407  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
408  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
409  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
410  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
411  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
412  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
413  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
414  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
415  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
416  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
417  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
418  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
419  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
420  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
421  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
422  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
423  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
424  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
425  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
426  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
427  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
428  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
429  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
430  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
431  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
432  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
433  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
434  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
435  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
436  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
437  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
438  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
439  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
440  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
441  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
442  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
443  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
444  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
445  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
446  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
447  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
448  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
449  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
450  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
451  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
452  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
453  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
454  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
455  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
456  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
457  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
458  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
459  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
460  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
461  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
462  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
463  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
464  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
465  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
466  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
467  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
468  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
469  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
470  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
471  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
472  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
473  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
474  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
475  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
476  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
477  // below not in RailGraphics
478  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
479 
480  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
481  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
482  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
483  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
484  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
485  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
486  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
487  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
488  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
489  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
490  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
491  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
492  HomeButton->Glyph->LoadFromResourceName(0, "Home");
493  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
494  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
495  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
496  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
497  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
498  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
499  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
500  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
501  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
502  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
503  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
504  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
505  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
506  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
507  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
508  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
509  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
510  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
511  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
512  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
513  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
514  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
515  SigPrefConsecButton->Glyph->LoadFromResourceName(0, "PrefTop");
516  SigPrefNonConsecButton->Glyph->LoadFromResourceName(0, "PrefBottom");
517  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
518  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
519  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
520  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
521 
522  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
523  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
524  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
525  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
526  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
527  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
528  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
529 
530  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
531  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
532 
533  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
534  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
535  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
536  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
537  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
538  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
539 
540 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
541  RailwayIcon = new TPicture;
542  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
543  Icon = RailwayIcon->Icon;
544  Application->Icon = RailwayIcon->Icon;
545 */
546 
547  AnsiString NL = '\n';
548  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
549  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
550  "Start new shuttle service from a feeder";
551 
552  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
553 
554  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
555  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
556  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
557 
558  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
559  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " +
560  NL + "R";
561 
562  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
563 
564  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
565  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
566  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
567  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
568  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
569 
570  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
571  "Arrival time, departure time (with no events between) + location";
572 
573  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
574  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
575 
576  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
577  "and semicolons may only be used to" + NL + "separate service components.";
578 
579  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
580 
581  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
582 
583  TTLabel1->Caption = TTLabelStr1;
584  TTLabel2->Caption = TTLabelStr2;
585  TTLabel3->Caption = TTLabelStr3;
586  TTLabel4->Caption = TTLabelStr4;
587  TTLabel5->Caption = TTLabelStr5;
588  TTLabel6->Caption = TTLabelStr6;
589  TTLabel7->Caption = TTLabelStr7;
590  TTLabel9->Caption = TTLabelStr9;
591  TTLabel11->Caption = TTLabelStr11;
592  TTLabel12->Caption = TTLabelStr12;
593  TTLabel13->Caption = TTLabelStr13;
594  TTLabel15->Caption = TTLabelStr15;
595 
596  SelectBitmap->TransparentColor = Utilities->clTransparent;
597  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
599 
600  TextBox->Color = clB3G3R3;
601  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
602  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
603 
604  if((Screen->Width < 1024) || (Screen->Height < 768))
605  {
606  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
607  }
608  SkipFormResizeEvent = true; // added at v2.1.0
609  MasterClock->Enabled = true;
610  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
611  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
612  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
613  // has to come after Visible = true or doesn't show
614  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
615  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
616  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
617  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
618  AllSetUpFlag = true;
619  MissedTicks = 0;
620  TotalTicks = 0;
622  SetLevel1Mode(131); // to reset background colour mode menu choices
623  Screen->Cursor = TCursor(-2); // Arrow
624  SkipFormResizeEvent = false; // added at v2.1.0
625  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
626 
627  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
628  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
629  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
630  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
631  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
632  HighlightPanel->Color = TColor(0x33CCFF);
634  MTBFEditBox->Visible = false; // new at v2.4.0
635  MTBFLabel->Visible = false;
639  CancelSelectionFlag = false;
640  TTStartTimePtr = 0;
641  TTFirstServicePtr = 0;
642  TTLastServicePtr = 0;
643  Track->OverrideAndHideSignalBridgeMessage = false; // added at v2.5.1 to allow facing signals before bridges - with a warning
644  ConflictPanel->Visible = false;
645  TTClockAdjustWarningPanel->Visible = false;
646  TTClockAdjustWarningHide = false;
647  LastNonCtrlOrShiftKeyDown = -1; // set to no key
648  ClipboardChecked = false;
649 
650  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
651 
652  // below added at v2.4.0 so able to load session files with the correct decimal point
653  Utilities->DecimalPoint = '.'; // default case is full stop
654  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
656  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
657  {
658  Utilities->SetLocaleResultOK = false;
659  }
660  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
661  struct lconv *conv = &Locale;
662  // read the locality conversion structure
663  conv = localeconv(); // this is what updates the structure
664  Utilities->DecimalPoint = conv->decimal_point[0];
665  }
666 
667  catch(const EFOpenError &e)
668  {
669  TMsgDlgButtons But;
670  But << mbOK;
671  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
672  Application->Terminate();
673  }
674 
675  catch(const Exception &e)
676  {
677  TMsgDlgButtons But;
678  But << mbOK;
679  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
680  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
681  ErrorLog(115, e.Message);
682  Application->Terminate();
683  }
684 }
685 
686 // ---------------------------------------------------------------------------
687 
689 {
690  // destructor
691  try
692  {
693  // rewrite ConfigFile with signal handedness, background colour & InitialDir values (may be same but no matter)
694  AnsiString ColourStr = "", SignalStr = "";
695  remove((CurDir + "\\Config.txt").c_str());
696  std::ofstream ConfigFile((CurDir + "\\Config.txt").c_str());
697  ColourStr = "black";
698  SignalStr = "left";
699  if(Utilities->clTransparent == TColor(0xFFFFFF))
700  {
701  ColourStr = "white";
702  }
703  else if(Utilities->clTransparent == TColor(0x330000))
704  {
705  ColourStr = "blue";
706  }
708  {
709  SignalStr = "right";
710  }
711  ConfigFile << AnsiString("Signals=") << SignalStr << '\n';
712  ConfigFile << AnsiString("BgndCol=") << ColourStr << '\n';
713  ConfigFile << AnsiString("RLYLocn=") << AnsiString(LoadRailwayDialog->InitialDir) << '\n';
714  ConfigFile << AnsiString("TTBLocn=") << AnsiString(TimetableDialog->InitialDir) << '\n';
715  ConfigFile << AnsiString("SSNLocn=") << AnsiString(LoadSessionDialog->InitialDir) << '\n';
716  ConfigFile.close();
717 
718  SkipFormResizeEvent = true; // added at v2.1.0
719  delete NonSigRouteStartMarker;
720  delete SigRouteStartMarker;
721  delete AutoRouteStartMarker;
722  delete PointFlash;
723  delete SelectBitmap;
724  delete TrainController;
725  delete EveryPrefDir;
726  delete ConstructRoute;
727  delete ConstructPrefDir;
728  delete AllRoutes;
729  delete Track;
730  delete TextHandler;
731  delete HiddenDisplay;
732  delete HiddenScreen;
733  delete Display;
734  delete RailGraphics;
735  delete Utilities;
736  DeleteFile(TempTTFileName); // added after v2.4.3 to prevent temporary files building up
737  }
738  catch(const Exception &e)
739  {
740  ErrorLog(116, e.Message);
741  }
742 }
744 
745 // ---------------------------------------------------------------------------
746 
747 void __fastcall TInterface::FormCreate(TObject *Sender)
748 {
749  // these functions have to be defined here to take effect when application activated & deactivated
750  try
751  {
752  Application->OnDeactivate = AppDeactivate;
753  Application->OnActivate = AppActivate;
754  }
755  catch(const Exception &e)
756  {
757  ErrorLog(117, e.Message);
758  }
759 }
760 
761 // ---------------------------------------------------------------------------
762 
763 void __fastcall TInterface::AppDeactivate(TObject *Sender)
764 {
765  // pause operation if operating & stop the master clock
766  try
767  {
769  {
770  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
771  {
772  // by Matt Blades 30/06/11
776  Screen->Cursor = TCursor(-2); // Arrow
777  Track->RouteFlashFlag = false;
778  ClearandRebuildRailway(48); // to get rid of displayed route
779  }
780  if(Track->PointFlashFlag)
781  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
782  {
784  Track->PointFlashFlag = false;
786  Screen->Cursor = TCursor(-2); // Arrow
787  }
790  }
791  MasterClock->Enabled = false;
792  ClipboardChecked = false; // added at v2.8.0 to force a check of the clipboard (via ClockTimer2 & SetTrackModemenu)
793  }
794  catch(const Exception &e)
795  {
796  ErrorLog(118, e.Message);
797  }
798 }
799 
800 // ---------------------------------------------------------------------------
801 
802 void __fastcall TInterface::AppActivate(TObject *Sender)
803 {
804  // restart the master clock providing Interface constructor has run
805  try
806  {
807  if(AllSetUpFlag)
808  {
809  MasterClock->Enabled = true;
810  }
811  }
812  catch(const Exception &e)
813  {
814  ErrorLog(119, e.Message);
815  }
816 }
817 
818 // ---------------------------------------------------------------------------
819 
820 UnicodeString TInterface::GetVersion()
821 {
822  DWORD VersionHandle;
823  DWORD VersionSize;
824  LPBYTE pBuffer;
825  UnicodeString strVersion = L"N/A";
826 
827  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
828  if(VersionSize)
829  {
830  pBuffer = new BYTE[VersionSize];
831 
832  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
833  {
834  VS_FIXEDFILEINFO *fi;
835  UINT buflen;
836 
837  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
838  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
839  {
840  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
841  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS));
842  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
843  }
844  }
845  delete[]pBuffer;
846  }
847  return(L" v" + strVersion);
848 }
849 
850 // ---------------------------------------------------------------------------
851 // Track Build Interface
852 // ---------------------------------------------------------------------------
853 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
854 {
855  try
856  {
857  TrainController->LogEvent("BuildTrackMenuItemClick");
858  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
860  SetLevel1Mode(0);
861  Utilities->CallLogPop(1159);
862  }
863  catch(const Exception &e)
864  {
865  ErrorLog(120, e.Message);
866  }
867 }
868 // ---------------------------------------------------------------------------
869 
870 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
871 {
872  try
873  {
874  TrainController->LogEvent("AddTrackButtonClick");
875  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
877  SetLevel1Mode(38);
880  Utilities->CallLogPop(1162);
881  }
882  catch(const Exception &e)
883  {
884  ErrorLog(121, e.Message);
885  }
886 }
887 
888 // ---------------------------------------------------------------------------
889 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
890 {
891  try
892  {
893  TrainController->LogEvent("SpeedButtonClick");
894  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
895  ReselectMenuItem->Enabled = false;
896  if(((TSpeedButton*)Sender)->Down)
897  {
898  CurrentSpeedButton = (TSpeedButton*)Sender;
899 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
900  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
901  if((Level2TrackMode == TrackSelecting) && (CurrentSpeedButton->Tag != 144))
902  // new addition at v2.6.0 to fill selected area with the element corresponding to CurrentSpeedButton
903  {
904  // 144 = level crossing & these not permitted
905  if((SelectRect.left != SelectRect.right) && (SelectRect.top != SelectRect.bottom) && SelectionValid)
906  {
907  Screen->Cursor = TCursor(-11); // Hourglass;
908  InfoPanel->Caption = "SELECTING: Filling area with chosen element";
909  bool FillSelectionFlag = false;
911  {
912  UnicodeString MessageStr =
913  "Click 'Yes' to fill the area with the chosen element or 'No' to abort.\n" "Existing elements won't be overwritten although track can\n"
914  "have platforms and non-station named location elements added.\n\nThis message will not be shown again.";
915  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
916  if(button == IDYES)
917  {
918  FillSelectionFlag = true;
919  }
920  }
921  if(FillSelectionFlag || FillSelectionMessageSentFlag)
922  {
923  bool TrackLinkingRequiredFlag = true;
924  for(int HLoc = SelectRect.left; HLoc < SelectRect.right; HLoc++)
925  {
926  for(int VLoc = SelectRect.top; VLoc < SelectRect.bottom; VLoc++)
927  {
928  if((HLoc != SelectRect.right) || (VLoc != SelectRect.bottom))
929  {
930  Track->PlotAndAddTrackElement(3, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, false);
931 // false for internal checks
932  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
933  }
934  else
935  {
936  Track->PlotAndAddTrackElement(4, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, true);
937 // internal checks true for last plot
938  }
939  }
940  }
941  }
942  Track->SetTrackFinished(false);
943  ClearandRebuildRailway(80); // to remove selection outline
944  SelectionValid = false;
945  Track->CopyFlag = false;
947  ResetSelectRect();
948  SetLevel1Mode(139);
950  SetLevel2TrackMode(66);
952  Screen->Cursor = TCursor(-2); // Arrow
953  ReselectMenuItem->Enabled = true; // allow when filling areas
954  }
955  }
956  }
957  else
958  {
959  CurrentSpeedButton = 0;
960  }
961  Utilities->CallLogPop(1163);
962  }
963  catch(const Exception &e)
964  {
965  ErrorLog(122, e.Message);
966  }
967 }
968 
969 // ---------------------------------------------------------------------------
970 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
971 {
972  try
973  {
974  TrainController->LogEvent("TrackOKButtonClick");
975  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
976  SelectionValid = false;
978  bool LocError;
979  int HLoc, VLoc;
980  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
981 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
982  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
983  // if successful repositions TrackVector & builds TrackMap
984  {
985  if(LocError) // links not complete or other error - show offending element
986  {
987  while((Display->DisplayOffsetH - HLoc) > 0)
988  {
989  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
990  }
991  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
992  {
994  }
995  while((Display->DisplayOffsetV - VLoc) > 0)
996  {
997  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
998  }
999  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
1000  {
1002  }
1004  Display->InvertElement(0, HLoc * 16, VLoc * 16);
1005  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
1006  ClearandRebuildRailway(1); // to clear inversion
1008  SetLevel1Mode(39);
1009  Level2TrackMode = AddTrack; // go to add track regardless of where started from
1010  SetLevel2TrackMode(3);
1011  Utilities->CallLogPop(0);
1012  return;
1013  }
1014  else
1015  {
1016  // reach here if there are no track elements
1017  ShowMessage("Unable to set any track links");
1019  SetLevel1Mode(40);
1021  SetLevel2TrackMode(4); // go to add track regardless of where started from
1022  Utilities->CallLogPop(1);
1023  return;
1024  }
1025  }
1026  else
1027  {
1028  // success ('TrackFinished' set in TryToConnectTrack)
1029  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
1030  ShowMessage("Successful Completion");
1031  }
1032 // success if reach here ('TrackFinished' set in TryToConnectTrack)
1033  if(Level2TrackMode == AddTrack)
1034  {
1036  SetLevel1Mode(41);
1037  SetLevel2TrackMode(5);
1038  }
1039  else
1040  {
1042  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
1043  }
1044  Utilities->CallLogPop(2);
1045  }
1046  catch(const Exception &e)
1047  {
1048  ErrorLog(3, e.Message);
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
1054 {
1055  try
1056  {
1057  TrainController->LogEvent("SetGapsButtonClick");
1058  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
1059  SelectionValid = false;
1060  ReselectMenuItem->Enabled = false;
1062  SetLevel1Mode(42);
1064  SetLevel2TrackMode(6);
1065  Utilities->CallLogPop(1164);
1066  }
1067  catch(const Exception &e)
1068  {
1069  ErrorLog(123, e.Message);
1070  }
1071 }
1072 
1073 // ---------------------------------------------------------------------------
1074 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
1075 {
1076  try
1077  {
1078  TrainController->LogEvent("AddTextButtonClick");
1079  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
1081  SetLevel1Mode(43);
1083  SetLevel2TrackMode(7);
1084  Utilities->CallLogPop(1165);
1085  }
1086  catch(const Exception &e)
1087  {
1088  ErrorLog(124, e.Message);
1089  }
1090 }
1091 
1092 // ---------------------------------------------------------------------------
1093 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1094 {
1095  try
1096  {
1097  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1098  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1100  SetLevel1Mode(44);
1102  SetLevel2TrackMode(8);
1103  Utilities->CallLogPop(1166);
1104  }
1105  catch(const Exception &e)
1106  {
1107  ErrorLog(125, e.Message);
1108  }
1109 }
1110 
1111 // ---------------------------------------------------------------------------
1112 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1113 {
1114  try
1115  {
1116  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1117  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1118  if(Key == '\x0D') // CR
1119  {
1120  if(TextBox->Text != "") // if blank then don't save
1121  {
1122  if(Display->GetFont()->Color == clB5G5R5) // white
1123  {
1124  TFont *TempFont = new TFont;
1125  TempFont->Assign(Display->GetFont());
1126  TempFont->Color = clB0G0R0; // change to black for vector & saving
1127  Display->SetFont(TempFont);
1128  delete TempFont;
1129  }
1130  TFont *DisplayFont = Display->GetFont();
1131  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1132  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1134  ResetChangedFileDataAndCaption(12, true); // moved here from MainScreenMouseDown2 after 2.7.0 in case nothing changed
1135  }
1136  EditMenu->Enabled = true;
1137  TextBox->Visible = false;
1138  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1139  }
1140  else if(Key == '\x1B') // escape
1141  {
1142  if(TextBox->Text != "")
1143  {
1144  ResetChangedFileDataAndCaption(28, true); // added here after 2.7.0 in case replaced existing text (which is selected) with blank
1145  }
1146  TextBox->Visible = false;
1147  }
1148  Utilities->CallLogPop(3);
1149  }
1150  catch(const Exception &e)
1151  {
1152  ErrorLog(4, e.Message);
1153  }
1154 }
1155 
1156 // ---------------------------------------------------------------------------
1157 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1158 {
1159  try
1160  {
1161  TrainController->LogEvent("LocationNameButtonClick");
1162  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1164  SetLevel1Mode(45);
1166  SetLevel2TrackMode(9);
1167  Utilities->CallLogPop(1167);
1168  }
1169  catch(const Exception &e)
1170  {
1171  ErrorLog(126, e.Message);
1172  }
1173 }
1174 
1175 // ---------------------------------------------------------------------------
1176 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1177 {
1178  try
1179  {
1180  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1181  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1182  if(Track->LNPendingList.empty())
1183  {
1184  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1186  SetLevel1Mode(46);
1188  SetLevel2TrackMode(10);
1189  Utilities->CallLogPop(4);
1190  return;
1191  }
1192  if(Key == '\x1B') // escape
1193  {
1194  Track->LNPendingList.clear(); // get rid of existing entry
1196  SetLevel1Mode(47);
1198  SetLevel2TrackMode(11);
1199  Utilities->CallLogPop(5);
1200  return;
1201  }
1202  if(Key == '\x0D')
1203  {
1204  Screen->Cursor = TCursor(-11); // Hourglass;
1206  ResetChangedFileDataAndCaption(8, true); // moved here after 2.7.0 from mainScreenMouseDown2 in case nothing changed
1207  AnsiString ExistingName;
1208  LocationNameTextBox->Text = LocationNameTextBox->Text.Trim();
1209 // added at v2.6.1 to prevent added spaces because they skip the different location same name chack
1210  if(Track->LNPendingList.front() > -1)
1211  {
1212  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1213  }
1214  else
1215  {
1216  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1217  }
1218  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1219  {
1220  // name allocated to a different location
1221  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1222  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1223  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1224  if(button == IDNO)
1225  {
1226  Track->LNPendingList.clear(); // get rid of existing entry
1227  Screen->Cursor = TCursor(-2); // Arrow
1229  SetLevel1Mode(48);
1231  SetLevel2TrackMode(12);
1232  Utilities->CallLogPop(6);
1233  return;
1234  }
1236  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1237  int HPos, VPos;
1238  bool UseExistingPosition = false;
1239  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1240  {
1241  ;
1242  } // condition not used
1243 
1244  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1245  // but, the location to be named may also have an existing name, in which case that needs to be erased
1246  // and the position re-used
1247  if(ExistingName != "")
1248  {
1249  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1250  {
1251  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1252  }
1253  }
1254  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1255  Screen->Cursor = TCursor(-2); // Arrow
1257  SetLevel1Mode(49);
1259  SetLevel2TrackMode(13);
1260  Utilities->CallLogPop(7);
1261  return;
1262  }
1263  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1264  {
1265  // same name being entered again
1266  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1267  // but in case the name is not already in text vector erase it and re-add it
1268  // if it wasn't in the vector erasing it has no effect
1269  int HPos, VPos;
1270  bool UseExistingPosition = false;
1271  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1272  {
1273  UseExistingPosition = true;
1274  }
1275  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1276  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1277  Screen->Cursor = TCursor(-2); // Arrow
1279  SetLevel1Mode(50);
1281  SetLevel2TrackMode(14);
1282  Utilities->CallLogPop(8);
1283  return;
1284  }
1285  else
1286  {
1287  // either a new name for an unnamed location, or a different name for a named location
1288  // check validity of entry
1289  AnsiString LocStr = LocationNameTextBox->Text;
1290  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1291  LocationNameTextBox->Text = LocStr; // reset this as used below
1292 /* drop this, now covered by ...Trim() above
1293  //strip leading spaces
1294  while((LocStr != "") && (LocStr[1] == ' '))
1295  {
1296  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1297  }
1298 */
1299  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1300  {
1301  Screen->Cursor = TCursor(-2); // Arrow
1302  ShowMessage("Location name can't begin with a number");
1304  SetLevel1Mode(51);
1306  SetLevel2TrackMode(15);
1307  Utilities->CallLogPop(776);
1308  return;
1309  }
1310  if(LocStr.Length() > 50)
1311  {
1312  Screen->Cursor = TCursor(-2); // Arrow
1313  ShowMessage("Location name too long, 50 characters maximum");
1315  SetLevel1Mode(122);
1317  SetLevel2TrackMode(55);
1318  Utilities->CallLogPop(1735);
1319  return;
1320  }
1321  for(int x = 1; x <= LocStr.Length(); x++)
1322  {
1323  char Ch = LocStr[x];
1324  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1325  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1326  {
1327  Screen->Cursor = TCursor(-2); // Arrow
1328  ShowMessage(
1329  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1331  SetLevel1Mode(52);
1333  SetLevel2TrackMode(16);
1334  Utilities->CallLogPop(777);
1335  return;
1336  }
1337  }
1338  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1339  {
1340  Screen->Cursor = TCursor(-2); // Arrow
1341  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1343  SetLevel1Mode(53);
1345  SetLevel2TrackMode(17);
1346  Utilities->CallLogPop(778);
1347  return;
1348  }
1349  Track->EnterLocationName(2, LocStr, false);
1350  // need to check if the location already has a name, and if so erase it from the textvector
1351  int HPos, VPos;
1352  bool UseExistingPosition = false;
1353  if(ExistingName != "")
1354  {
1355  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1356  {
1357  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1358  }
1359  }
1360  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1361  Screen->Cursor = TCursor(-2); // Arrow
1363  SetLevel1Mode(54);
1365  SetLevel2TrackMode(18);
1366  Utilities->CallLogPop(9);
1367  return;
1368  }
1369  }
1370  Screen->Cursor = TCursor(-2); // Arrow
1371  Utilities->CallLogPop(10);
1372  }
1373  catch(const Exception &e)
1374  {
1375  ErrorLog(5, e.Message);
1376  }
1377 }
1378 
1379 // ---------------------------------------------------------------------------
1380 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1381 {
1382  try
1383  {
1384  TrainController->LogEvent("SetLengthsButtonClick");
1385  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1386  SelectLengthsFlag = false;
1387  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1389  SetLevel1Mode(55);
1391  SetLevel2TrackMode(19);
1392  Utilities->CallLogPop(1168);
1393  }
1394  catch(const Exception &e)
1395  {
1396  ErrorLog(127, e.Message);
1397  }
1398 }
1399 
1400 // ---------------------------------------------------------------------------
1401 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1402 {
1403  try
1404  {
1405  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1406  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1407  ResetChangedFileDataAndCaption(4, true); // moved here after 2.7.0 so only need to save if something changed
1408  int Dist = 0, SpeedLimit = 0;
1409  AnsiString DistanceStr = DistanceBox->Text;
1410  if(SelectLengthsFlag && (DistanceStr == ""))
1411  {
1412  DistanceStr = "No change";
1413  }
1414  AnsiString SpeedStr = SpeedLimitBox->Text;
1415  if(SelectLengthsFlag && (SpeedStr == ""))
1416  {
1417  SpeedStr = "No change";
1418  }
1419  if(SelectLengthsFlag)
1420  {
1421  if(DistanceStr == "No change")
1422  {
1423  Dist = -1; // i.e.don't change
1424  }
1425  if(SpeedStr == "No change")
1426  {
1427  SpeedLimit = -1; // i.e.don't change
1428  }
1429  }
1430  else
1431  {
1432  if(DistanceStr == AnsiString(OverallDistance))
1433  {
1434  Dist = -1; // i.e.don't change
1435  }
1436  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1437  {
1438  SpeedLimit = -1; // i.e.don't change
1439  }
1440  }
1441  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1442  {
1443  ShowMessage("One or more entries too long");
1444  Utilities->CallLogPop(11);
1445  return;
1446  }
1447  if((DistanceStr == "") || (SpeedStr == ""))
1448  {
1449  ShowMessage("One or more entries blank");
1450  Utilities->CallLogPop(12);
1451  return;
1452  }
1453  if(SelectLengthsFlag && (Dist != -1))
1454  {
1455  for(int x = 1; x <= DistanceStr.Length(); x++)
1456  {
1457  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1458  {
1459  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1460  Utilities->CallLogPop(1415);
1461  return;
1462  }
1463  }
1464  }
1465  if(!SelectLengthsFlag)
1466  {
1467  for(int x = 1; x <= DistanceStr.Length(); x++)
1468  {
1469  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1470  {
1471  ShowMessage("Distance must be a positive whole number");
1472  Utilities->CallLogPop(13);
1473  return;
1474  }
1475  }
1476  }
1477  if(SelectLengthsFlag && (SpeedLimit != -1))
1478  {
1479  for(int x = 1; x <= SpeedStr.Length(); x++)
1480  {
1481  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1482  {
1483  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1484  Utilities->CallLogPop(1416);
1485  return;
1486  }
1487  }
1488  }
1489  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1490  {
1491  for(int x = 1; x <= SpeedStr.Length(); x++)
1492  {
1493  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1494  {
1495  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1496  Utilities->CallLogPop(14);
1497  return;
1498  }
1499  }
1500  }
1501  if(Dist != -1)
1502  {
1503  Dist = DistanceStr.ToInt();
1504  }
1505  if(SpeedLimit != -1)
1506  {
1507  SpeedLimit = SpeedStr.ToInt();
1508  }
1509 /* don't need this with new condition below
1510  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1511  {
1512  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1513  Dist = 20;
1514  }
1515 */
1516  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1517  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1518  {
1519  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1520  Utilities->CallLogPop(15);
1521  return;
1522  }
1523  DistanceBox->Text = "";
1524  SpeedLimitBox->Text = "";
1525  if(SelectLengthsFlag)
1526  {
1527  int LowSelectHLoc = SelectBitmapHLoc;
1528  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1529  int LowSelectVLoc = SelectBitmapVLoc;
1530  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1531  bool FoundFlag;
1532  bool NamedLocPresent = false;
1533  if((Dist != -1) && (Dist != DefaultTrackLength))
1534  {
1535  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1536  {
1537  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1538  {
1540  {
1541  NamedLocPresent = true;
1542  }
1543  }
1544  }
1545  }
1546  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1547  {
1548  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
1549  }
1550  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1551  {
1552  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
1553  }
1554  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1555  {
1556  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1557  {
1558  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1559  if(FoundFlag)
1560  {
1561  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1562  {
1563  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1564  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1565  {
1566  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1567  }
1568  }
1569  if(SpeedLimit > -1)
1570  {
1571  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1572  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1573  {
1574  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1575  }
1576  }
1577  }
1578  }
1579  }
1580  TrackLengthPanel->Visible = false;
1581  SelectLengthsFlag = false; // go back to normal distance setting mode
1582  }
1583  else
1584  {
1585  SetTrackLengths(1, Dist, SpeedLimit);
1586  }
1588  SetLevel1Mode(57);
1590  SetLevel2TrackMode(21);
1591  Utilities->CallLogPop(16);
1592  }
1593  catch(const Exception &e)
1594  {
1595  ErrorLog(6, e.Message);
1596  }
1597 }
1598 
1599 // ---------------------------------------------------------------------------
1600 void __fastcall TInterface::LengthCancelButtonClick(TObject * Sender)
1601 {
1602  try
1603  {
1604  TrainController->LogEvent("LengthCancelButtonClick");
1605  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1606  DistanceBox->Text = "";
1607  SpeedLimitBox->Text = "";
1608  TrackLengthPanel->Visible = false;
1609  SelectLengthsFlag = false; // go back to normal distance setting mode
1611  SetLevel1Mode(59);
1613  SetLevel2TrackMode(23);
1614  Utilities->CallLogPop(1169);
1615  }
1616  catch(const Exception &e)
1617  {
1618  ErrorLog(128, e.Message);
1619  }
1620 }
1621 
1622 // ---------------------------------------------------------------------------
1623 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1624 {
1625  try
1626  {
1627  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1628  TMsgDlgButtons Buttons;
1629  Buttons << mbYes << mbNo;
1630  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1631  {
1632  // leave all as was before
1633  Utilities->CallLogPop(17);
1634  return;
1635  }
1636  else
1637  {
1638  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1639  ResetChangedFileDataAndCaption(25, true); // added after 2.7.0 so only need to save if something changed
1640  DistanceBox->Text = "";
1641  SpeedLimitBox->Text = "";
1642  if(SelectLengthsFlag)
1643  {
1644  int LowSelectHLoc = SelectBitmapHLoc;
1645  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1646  int LowSelectVLoc = SelectBitmapVLoc;
1647  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1648  bool FoundFlag;
1649  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1650  {
1651  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1652  {
1653  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1654  if(FoundFlag)
1655  {
1657  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1658  {
1660  }
1662  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1663  {
1665  }
1666  }
1667  }
1668  }
1669  TrackLengthPanel->Visible = false;
1670 // ClearandRebuildRailway(47); don't need this
1671  SelectLengthsFlag = false; // go back to normal distance setting mode
1672  }
1673  else
1674  {
1675  TrackLengthPanel->Visible = false;
1676  bool FoundFlag;
1677  if(ConstructPrefDir->PrefDirSize() == 0)
1678  {
1679  Utilities->CallLogPop(1120);
1680  return;
1681  }
1682  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1683  {
1684  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1685  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1686  FoundFlag));
1687  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1688  // only set the relevant track to default length & speed limit
1689  {
1690  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1691  {
1692  TrackElement.Length01 = DefaultTrackLength;
1693  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1694  }
1695  else
1696  {
1697  TrackElement.Length23 = DefaultTrackLength;
1698  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1699  }
1700  }
1701  else // any other 1 track element, including platforms being present
1702  {
1703  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1704  {
1705  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1706  AnsiString(TrackElement.VLoc));
1707  }
1708  TrackElement.Length01 = DefaultTrackLength;
1709  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1710  TrackElement.Length23 = -1;
1711  TrackElement.SpeedLimit23 = -1;
1712  }
1713  }
1714  }
1716  SetLevel1Mode(61);
1718  SetLevel2TrackMode(25);
1719  }
1720  Utilities->CallLogPop(18);
1721  }
1722  catch(const Exception &e)
1723  {
1724  ErrorLog(7, e.Message);
1725  }
1726 }
1727 
1728 // ---------------------------------------------------------------------------
1729 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1730 {
1731  try
1732  {
1733  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1734  TMsgDlgButtons Buttons;
1735  Buttons << mbYes << mbNo;
1736  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1737  {
1738  // leave all as was before
1739  Utilities->CallLogPop(19);
1740  return;
1741  }
1742  else
1743  {
1745  }
1746  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1747  ResetChangedFileDataAndCaption(26, true); // added after 2.7.0 so only need to save if something changed
1748  DistanceBox->Text = "";
1749  SpeedLimitBox->Text = "";
1750  TrackLengthPanel->Visible = false;
1751  SelectLengthsFlag = false; // go back to normal distance setting mode
1753  SetLevel1Mode(63);
1755  SetLevel2TrackMode(27);
1756  Utilities->CallLogPop(20);
1757  }
1758  catch(const Exception &e)
1759  {
1760  ErrorLog(8, e.Message);
1761  }
1762 }
1763 
1764 // ---------------------------------------------------------------------------
1765 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1766 {
1767  try
1768  {
1769  TrainController->LogEvent("ExitTrackButtonClick");
1770  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1771  if(Level2TrackMode == CutMoving)
1772  {
1773  Level2TrackMode = Pasting; // to paste the selection
1774  SetLevel2TrackMode(53);
1775  }
1776  DevelopmentPanel->Visible = false; // development use only
1777  ScreenGridFlag = false;
1778  SelectionValid = false;
1779  Track->SelectGraphicVector.clear();
1780  // delete all unwanted TPictures in UserGraphicMap
1781  if(!Track->UserGraphicMap.empty()) // if empty skip it
1782  {
1783  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1784  do
1785  {
1786  bool GraphicFoundInVector = false;
1787  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1788  {
1789  if(UGMIt->first == UGVIt->FileName)
1790  {
1791  GraphicFoundInVector = true;
1792  break;
1793  }
1794  }
1795  if(!GraphicFoundInVector)
1796  {
1797  delete UGMIt->second;
1798  Track->UserGraphicMap.erase(UGMIt);
1799  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1800  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1801  }
1802  else
1803  {
1804  UGMIt++;
1805  }
1806  }
1807  while(UGMIt != Track->UserGraphicMap.end());
1808  }
1809  Level1Mode = BaseMode;
1810  SetLevel1Mode(2);
1811  Utilities->CallLogPop(1170);
1812  }
1813  catch(const Exception &e)
1814  {
1815  ErrorLog(129, e.Message);
1816  }
1817 }
1818 
1819 // ---------------------------------------------------------------------------
1820 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1821 {
1822  try
1823  {
1824  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1825  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1826  if(TextOrUserGraphicGridVal == 1)
1827  {
1829  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1830  }
1831  else if(TextOrUserGraphicGridVal == 2)
1832  {
1834  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1835  }
1836  else if(TextOrUserGraphicGridVal == 4)
1837  {
1839  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1840  }
1841  else if(TextOrUserGraphicGridVal == 8)
1842  {
1844  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1845  }
1846  else
1847  {
1849  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1850  }
1851  Utilities->CallLogPop(1171);
1852  }
1853  catch(const Exception &e)
1854  {
1855  ErrorLog(130, e.Message);
1856  }
1857 }
1858 
1859 // ---------------------------------------------------------------------------
1860 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1861 {
1862  try
1863  {
1864  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1865  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1867  {
1869  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1870  }
1872  {
1874  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1875  }
1877  {
1879  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1880 // set all signal glyphs to ground signals
1882  }
1883  else
1884  {
1886  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1887 // set all signal glyphs to normal signals
1889  }
1890  Utilities->CallLogPop(1869);
1891  }
1892  catch(const Exception &e)
1893  {
1894  ErrorLog(180, e.Message);
1895  }
1896 }
1897 
1898 // ---------------------------------------------------------------------------
1899 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1900 {
1901  try
1902  {
1903  TrainController->LogEvent("FontButtonClick");
1904  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1905  FontDialog->Font = Display->GetFont(); // sets the dialog box font to the currently used font
1906  FontDialog->Execute(); // this displays the dialog box
1907  if(FontDialog->Font->Color == clB5G5R5) // white
1908  {
1909  FontDialog->Font->Color = clB0G0R0; // black - don't store white in font, will display black as white on dark backgrounds
1910  }
1911  Display->SetFont(FontDialog->Font); // sets the displayed font to the output from the dialog box
1912  if(TextBox->Visible)
1913  {
1914  TextBox->SetFocus();
1915  }
1916  else if(LocationNameTextBox->Visible)
1917  {
1918  LocationNameTextBox->SetFocus();
1919  }
1920  Utilities->CallLogPop(1172);
1921  }
1922  catch(const Exception &e)
1923  {
1924  ErrorLog(131, e.Message);
1925  }
1926 }
1927 
1928 // ---------------------------------------------------------------------------
1929 
1930 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1931 {
1932  try
1933  {
1934  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1935  if(ScreenGridFlag)
1936  {
1937  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1938  ScreenGridFlag = false;
1939  }
1940  else
1941  {
1942  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1943  ScreenGridFlag = true;
1944  }
1946  Utilities->CallLogPop(89);
1947  }
1948  catch(const Exception &e)
1949  {
1950  ErrorLog(33, e.Message);
1951  }
1952 }
1953 
1954 // ---------------------------------------------------------------------------
1955 // PrefDir Interface
1956 // ---------------------------------------------------------------------------
1957 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1958 {
1959  try
1960  {
1961  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1962  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1964  SetLevel1Mode(3);
1965  Utilities->CallLogPop(1173);
1966  }
1967  catch(const Exception &e)
1968  {
1969  ErrorLog(132, e.Message);
1970  }
1971 }
1972 
1973 // ---------------------------------------------------------------------------
1974 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1975 {
1976  try
1977  {
1978  TrainController->LogEvent("AddPrefDirButtonClick");
1979  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1980  if(ConstructPrefDir->PrefDirSize() == 0)
1981  {
1982  ShowMessage("No preferred direction selection");
1983  Utilities->CallLogPop(22);
1984  return;
1985  }
1986  Screen->Cursor = TCursor(-11); // Hourglass;
1988  {
1990  }
1992  SetLevel1Mode(4);
1993  Screen->Cursor = TCursor(-2); // Arrow
1994  Utilities->CallLogPop(23);
1995  }
1996  catch(const Exception &e)
1997  {
1998  ErrorLog(10, e.Message);
1999  }
2000 }
2001 
2002 // ---------------------------------------------------------------------------
2003 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
2004 {
2005  try
2006  {
2007  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
2008  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
2009  TMsgDlgButtons Buttons;
2010  Buttons << mbYes << mbNo;
2011  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
2012  {
2013  Utilities->CallLogPop(24);
2014  return;
2015  }
2016  // leave all as was before pressed DeleteAllPrefDirButton
2017  else
2018  {
2023  SetLevel1Mode(5);
2024  }
2025  Utilities->CallLogPop(25);
2026  }
2027  catch(const Exception &e)
2028  {
2029  ErrorLog(11, e.Message);
2030  }
2031 }
2032 // ---------------------------------------------------------------------------
2033 
2034 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
2035 {
2036  try
2037  {
2038  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
2039  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
2040  ResetChangedFileDataAndCaption(18, false);
2041 // RlyFile = false; - don't alter this just for PrefDir changes
2042  Screen->Cursor = TCursor(-11); // Hourglass;
2043  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
2044  {
2047  }
2050  SetLevel1Mode(81); // all PrefDir truncated
2051  Screen->Cursor = TCursor(-2); // Arrow
2052  Utilities->CallLogPop(1591);
2053  }
2054  catch(const Exception &e)
2055  {
2056  ErrorLog(46, e.Message);
2057  }
2058 }
2059 
2060 // ---------------------------------------------------------------------------
2061 
2062 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
2063 {
2064  try
2065  {
2066  TrainController->LogEvent("ExitPrefDirButtonClick");
2067  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
2068  Level1Mode = BaseMode;
2069  SetLevel1Mode(6);
2070  Utilities->CallLogPop(1554);
2071  }
2072  catch(const Exception &e)
2073  {
2074  ErrorLog(133, e.Message);
2075  }
2076 }
2077 
2078 // ---------------------------------------------------------------------------
2079 // Operate Railway Interface
2080 // ---------------------------------------------------------------------------
2081 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
2082 {
2083  try
2084  {
2085  TrainController->LogEvent("OperateRailwayMenuItemClick");
2086  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
2087  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
2088  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
2089  Level1Mode = OperMode;
2090  SetLevel1Mode(7);
2091  Utilities->CallLogPop(26);
2092  }
2093  catch(const Exception &e)
2094  {
2095  ErrorLog(12, e.Message);
2096  }
2097 }
2098 
2099 // ---------------------------------------------------------------------------
2100 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
2101 {
2102  try
2103  {
2104  TrainController->LogEvent("StartOperationButtonClick");
2105  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
2107  {
2109  SetLevel2OperMode(0);
2110  }
2111  else
2112  {
2114  SetLevel2OperMode(1);
2115  }
2116  Utilities->CallLogPop(1175);
2117  }
2118  catch(const Exception &e)
2119  {
2120  ErrorLog(37, e.Message);
2121  }
2122 }
2123 
2124 // ---------------------------------------------------------------------------
2125 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
2126 // must have PrefDirs to be available
2127 {
2128  try
2129  {
2130  TrainController->LogEvent("AutoSigsButtonClick");
2131  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
2132  AutoSigsFlag = true;
2133  PreferredRoute = true;
2134  ConsecSignalsRoute = true;
2135 
2136  AutoSigsButton->Enabled = false;
2137  SigPrefConsecButton->Enabled = true;
2138  SigPrefNonConsecButton->Enabled = true;
2139  UnrestrictedButton->Enabled = true;
2140 
2141  InfoPanel->Visible = true;
2142  if(Level2OperMode == PreStart)
2143  {
2144  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2145  }
2146  else
2147  {
2148  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2149  }
2150  InfoCaptionStore = InfoPanel->Caption;
2151  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2152  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2153  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2155  Utilities->CallLogPop(28);
2156  }
2157  catch(const Exception &e)
2158  {
2159  ErrorLog(14, e.Message);
2160  }
2161 }
2162 
2163 // ---------------------------------------------------------------------------
2164 
2165 void __fastcall TInterface::SigPrefConsecButtonClick(TObject *Sender)
2166 // must have PrefDirs to be available
2167 {
2168  try
2169  {
2170  TrainController->LogEvent("SigPrefButtonClick");
2171  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2172  AutoSigsFlag = false;
2173  PreferredRoute = true;
2174  ConsecSignalsRoute = true;
2175 
2176  AutoSigsButton->Enabled = true;
2177  SigPrefConsecButton->Enabled = false;
2178  SigPrefNonConsecButton->Enabled = true;
2179  UnrestrictedButton->Enabled = true;
2180 
2181  InfoPanel->Visible = true;
2182  if(Level2OperMode == PreStart)
2183  {
2184  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2185  }
2186  else
2187  {
2188  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2189  }
2190  InfoCaptionStore = InfoPanel->Caption;
2191  AutoRouteStartMarker->PlotOriginal(43, Display); // if overlay not plotted will ignore
2192  SigRouteStartMarker->PlotOriginal(44, Display); // if overlay not plotted will ignore
2193  NonSigRouteStartMarker->PlotOriginal(45, Display); // if overlay not plotted will ignore
2195  Utilities->CallLogPop(2265);
2196  }
2197  catch(const Exception &e)
2198  {
2199  ErrorLog(221, e.Message);
2200  }
2201 }
2202 
2203 // ---------------------------------------------------------------------------
2204 
2205 void __fastcall TInterface::SigPrefNonConsecButtonClick(TObject *Sender)
2206 // must have PrefDirs to be available
2207 {
2208  try
2209  {
2210  TrainController->LogEvent("SigPrefButtonClick");
2211  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2212  AutoSigsFlag = false;
2213  PreferredRoute = true;
2214  ConsecSignalsRoute = false;
2215 
2216  AutoSigsButton->Enabled = true;
2217  SigPrefConsecButton->Enabled = true;
2218  SigPrefNonConsecButton->Enabled = false;
2219  UnrestrictedButton->Enabled = true;
2220 
2221  InfoPanel->Visible = true;
2222  if(Level2OperMode == PreStart)
2223  {
2224  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2225  }
2226  else
2227  {
2228  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2229  }
2230  InfoCaptionStore = InfoPanel->Caption;
2231  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2232  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2233  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2235  Utilities->CallLogPop(29);
2236  }
2237  catch(const Exception &e)
2238  {
2239  ErrorLog(15, e.Message);
2240  }
2241 }
2242 
2243 // ---------------------------------------------------------------------------
2244 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2245 {
2246  try
2247  {
2248  TrainController->LogEvent("NoSigNonPrefButtonClick");
2249  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2250  AutoSigsFlag = false;
2251  PreferredRoute = false;
2252  ConsecSignalsRoute = false;
2253  if(EveryPrefDir->PrefDirSize() > 0)
2254  {
2255  AutoSigsButton->Enabled = true;
2256  SigPrefConsecButton->Enabled = true;
2257  SigPrefNonConsecButton->Enabled = true;
2258  UnrestrictedButton->Enabled = false;
2259  }
2260  else
2261  {
2262  AutoSigsButton->Enabled = false;
2263  SigPrefConsecButton->Enabled = false;
2264  SigPrefNonConsecButton->Enabled = false;
2265  UnrestrictedButton->Enabled = false;
2266  }
2267  InfoPanel->Visible = true;
2268  if(Level2OperMode == PreStart)
2269  {
2270  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2271  }
2272  else
2273  {
2274  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2275  }
2276  InfoCaptionStore = InfoPanel->Caption;
2277  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2278  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2279  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2281  Utilities->CallLogPop(30);
2282  }
2283  catch(const Exception &e)
2284  {
2285  ErrorLog(16, e.Message);
2286  }
2287 }
2288 
2289 // ---------------------------------------------------------------------------
2290 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2291 {
2292  try
2293  {
2294  TrainController->LogEvent("RouteCancelButtonClick");
2295  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2296  RouteCancelFlag = true;
2297  InfoPanel->Visible = true;
2298  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2299  RouteCancelButton->Enabled = false;
2300  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2301  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2302  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2303  Utilities->CallLogPop(1176);
2304  }
2305  catch(const Exception &e)
2306  {
2307  ErrorLog(35, e.Message);
2308  }
2309 }
2310 
2311 // ---------------------------------------------------------------------------
2312 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2313 {
2314  try
2315  {
2316  TrainController->LogEvent("PerformanceLogButtonClick");
2317  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2319  {
2320  ShowPerformancePanel = true;
2321  PerformancePanel->Visible = true;
2322  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2323  }
2324  else
2325  {
2326  ShowPerformancePanel = false;
2327  PerformancePanel->Visible = false;
2328  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2329  }
2330  Utilities->CallLogPop(1177);
2331  }
2332  catch(const Exception &e)
2333  {
2334  ErrorLog(36, e.Message);
2335  }
2336 }
2337 // ---------------------------------------------------------------------------
2338 
2339 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2340 {
2341  try
2342  {
2343  TrainController->LogEvent("ExitOperationButtonClick");
2344  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2346  {
2347  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2348  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2350  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2351  TrainController->BaseTime = TDateTime::CurrentDateTime();
2353  if(button == IDNO)
2354  {
2355  Utilities->CallLogPop(751);
2356  return;
2357  }
2358  }
2359  Track->ResetSignals(1);
2360  Track->ResetPoints(1);
2361  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2362  Utilities->PerformanceFile.close();
2365  RouteMode = None;
2366  PreferredRoute = true; // default starting conditions
2367  ConsecSignalsRoute = true; // default starting conditions
2369  ShowPerformancePanel = false;
2370  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2371  ShowOperatorActionPanel = false; // new at v2.2.0
2372  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2373  PerformanceLogBox->Lines->Clear();
2374  PerformancePanel->Visible = false;
2375  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2376  PerformancePanel->Left = MainScreen->Left;
2377 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2378  OAListBox->Clear();
2379  OperatorActionPanel->Visible = false;
2380  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2381  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
2382  ;
2384  AllRoutes->LockedRouteVector.clear();
2385  Level1Mode = BaseMode;
2386  SetLevel1Mode(8); // calls Clearand...
2387  Utilities->CallLogPop(1555);
2388  }
2389  catch(const Exception &e)
2390  {
2391  ErrorLog(13, e.Message);
2392  }
2393 }
2394 
2395 // ---------------------------------------------------------------------------
2396 // Menu Interface (for items not already covered above)
2397 // ---------------------------------------------------------------------------
2398 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2399 {
2400  try
2401  {
2402  TrainController->LogEvent("LoadRailwayMenuItemClick");
2403  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2404  if(!ClearEverything(1))
2405  {
2406  Utilities->CallLogPop(1139);
2407  return;
2408  }
2409  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2410  // changed at v2.0.0 (Embarcadero change) to show all files together
2411  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2412  if(LoadRailwayDialog->Execute())
2413  {
2414  if(LoadRailwayDialog->InitialDir != TPath::GetDirectoryName(LoadRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
2415  {
2416  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2417  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2418  }
2419  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2420  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2421  }
2422  // else ShowMessage("Load Aborted"); drop this
2423  // Display->Update(); //display updated in ClearandRebuildRailway
2424  Track->CalcHLocMinEtc(9);
2425  Level1Mode = BaseMode;
2428  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2429  Utilities->CallLogPop(31);
2430  }
2431  catch(const Exception &e)
2432  {
2433  ErrorLog(17, e.Message);
2434  }
2435 }
2436 // ---------------------------------------------------------------------------
2437 
2438 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2439 {
2440  // display of the loaded railway covered in the calling routine
2441  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2442  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2443  {
2444  Screen->Cursor = TCursor(-11); // Hourglass;
2445  std::ifstream VecFile(LoadFileName.c_str());
2446  if(!(VecFile.fail()))
2447  {
2448  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2449  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2450  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2451  bool GraphicsFollow = false;
2452  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2453 // load track elements
2454  Track->LoadTrack(1, VecFile, GraphicsFollow);
2455 // load text elements
2456  TextHandler->LoadText(0, VecFile);
2457 // load PrefDir elements
2458  EveryPrefDir->LoadPrefDir(0, VecFile);
2459  if(GraphicsFollow)
2460  {
2461 // load user graphics
2462  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2463  }
2464  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2465  VecFile.close();
2466  Display->DisplayOffsetHHome = TempOffsetHHome;
2467  Display->DisplayOffsetVHome = TempOffsetVHome;
2469 
2470  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2471  TempFont->Style.Clear();
2472  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2473  TempFont->Size = 10;
2474  TempFont->Color = clB0G0R0;
2475  TempFont->Charset = (TFontCharset)(0);
2476  MainScreen->Canvas->Font->Assign(TempFont);
2477  delete TempFont;
2478 
2479 // calculate starting zoomed out offset values - same as when zoom out button clicked
2480  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2481 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2482  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2483  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2484  if((LeftExcess > 0) && (RightExcess > 0))
2485  {
2486  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2487  }
2488  else if((LeftExcess > 0) && (RightExcess <= 0))
2489  {
2490  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2491  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2492  }
2493  else if((LeftExcess <= 0) && (RightExcess > 0))
2494  {
2495  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2496  }
2497  else
2498  {
2499  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2500 
2501  }
2502  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2503  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2504  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2505  if((TopExcess > 0) && (BotExcess > 0))
2506  {
2507  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2508  }
2509  else if((TopExcess > 0) && (BotExcess <= 0))
2510  {
2511  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2512  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2513  }
2514  else if((TopExcess <= 0) && (BotExcess > 0))
2515  {
2516  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2517  }
2518  else
2519  {
2520  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2521  }
2522 // all above same as when zoom out button clicked
2523  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2525 
2526  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2527  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2528  {
2529  Track->DuplicatedLocationName(1, true);
2530  char LastChar = SavedFileName[SavedFileName.Length()];
2531  if((LastChar == 'y') || (LastChar == 'Y'))
2532  {
2533  if(!(Track->IsReadyForOperation(false)))
2534  {
2535  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2536  SavedFileName = "";
2537  RlyFile = false;
2538  RailwayTitle = "";
2539  TimetableTitle = "";
2540  SetCaption(5);
2541  Track->CalcHLocMinEtc(1);
2542  Screen->Cursor = TCursor(-2); // Arrow
2543  Level1Mode = BaseMode;
2544  SetLevel1Mode(9);
2545  Utilities->CallLogPop(1136);
2546  return;
2547  }
2548  else
2549  {
2550  RlyFile = true;
2551  }
2552  }
2553  else
2554  {
2555  RlyFile = false;
2556  }
2557  }
2558  else
2559  {
2560  RlyFile = false;
2561  }
2562  FileChangedFlag = false;
2563  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2564  {
2565  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2566  {
2567  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2568  TimetableTitle = "";
2569  SetCaption(6);
2570  break;
2571  }
2572  }
2573  } // if(VecFile)
2574  else
2575  {
2576  ShowMessage("File open failed prior to load");
2577  }
2578  Screen->Cursor = TCursor(-2); // Arrow
2579  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2580  else
2581  {
2582  ShowMessage("File integrity check failed - unable to load");
2583  }
2584  Utilities->CallLogPop(1774);
2585 }
2586 
2587 // ---------------------------------------------------------------------------
2588 
2589 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2590 {
2591 // save under existing name
2592 // no need to alter RlyFile for saving under existing name
2593 
2594  try
2595  {
2596  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2597  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2598  Screen->Cursor = TCursor(-11); // Hourglass;
2599  std::ofstream VecFile(SavedFileName.c_str());
2600  if(!(VecFile.fail()))
2601  {
2605  // save track elements
2606  if(Track->UserGraphicVector.empty())
2607  {
2608  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2609  }
2610  else
2611  {
2612  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2613  }
2614  // save text elements
2615  TextHandler->SaveText(0, VecFile);
2616  // save PrefDir elements
2617  EveryPrefDir->SavePrefDirVector(0, VecFile);
2618  if(!Track->UserGraphicVector.empty())
2619  {
2620  // save user graphics
2621  Track->SaveUserGraphics(0, VecFile);
2622  }
2623  FileChangedFlag = false;
2624  VecFile.close();
2625  }
2626  else
2627  {
2628  ShowMessage("File open failed prior to save");
2629  }
2630  Screen->Cursor = TCursor(-2); // Arrow
2631  Level1Mode = BaseMode;
2632  SetLevel1Mode(12); // to disable the save option
2633  Utilities->CallLogPop(1178);
2634  }
2635  catch(const Exception &e)
2636  {
2637  ErrorLog(135, e.Message);
2638  }
2639 }
2640 
2641 // ---------------------------------------------------------------------------
2642 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2643 {
2644  try
2645  {
2646  TrainController->LogEvent("SaveAsMenuItemClick");
2647  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2648  SaveAsSubroutine(0);
2649  Utilities->CallLogPop(32);
2650  }
2651  catch(const Exception &e)
2652  {
2653  ErrorLog(18, e.Message);
2654  }
2655 }
2656 
2657 // ---------------------------------------------------------------------------
2658 
2659 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2660 {
2661  // need to stop clock in case invoke during operation
2662  try
2663  {
2664  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2665  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2666  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2667  {
2668  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2669  Utilities->CallLogPop(1695);
2670  return;
2671  }
2672  Screen->Cursor = TCursor(-11); // Hourglass;
2673  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2675  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2676  // format "16/06/2009 20:55:17"
2677  // avoid characters in filename:= / \ : * ? " < > |
2678  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2679  AnsiString ShortName = "";
2680  for(int x = ImageFileName.Length(); x > 0; x--)
2681  {
2682  if(ImageFileName[x] == '\\')
2683  {
2684  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2685  break;
2686  }
2687  }
2688  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2689  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2690  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2691 
2692  int HPosMin = Track->GetHLocMin() * 16;
2693  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2694  int VPosMin = Track->GetVLocMin() * 16;
2695  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2696  RailwayImage->Width = HPosMax - HPosMin;
2697  RailwayImage->Height = VPosMax - VPosMin;
2698 
2699  // need to check if there is any text that extends past HPosMax or below VPosMax
2700  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2701  if(!TextHandler->TextVector.empty())
2702  {
2703  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2704  {
2705  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2706  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2707  if(NewWidth > RailwayImage->Width)
2708  {
2709  RailwayImage->Width = NewWidth;
2710  }
2711  if(NewHeight > RailwayImage->Height)
2712  {
2713  RailwayImage->Height = NewHeight;
2714  }
2715  }
2716  }
2717  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2718  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2719  RailwayImage->Canvas->FillRect(Rect);
2720 
2721  // write graphics first so text & track overwrite
2722  Track->WriteGraphicsToImage(0, RailwayImage);
2723  // then write text so track overwrites
2724  TextHandler->WriteTextToImage(0, RailwayImage);
2725  Track->WriteTrackToImage(0, RailwayImage);
2726 
2727  RailwayImage->SaveToFile(ImageFileName);
2728  delete RailwayImage;
2729  TrainController->BaseTime = TDateTime::CurrentDateTime();
2731  Screen->Cursor = TCursor(-2); // Arrow
2732  Utilities->CallLogPop(1535);
2733  }
2734  catch(const Exception &e)
2735  {
2736  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2737  {
2738  Screen->Cursor = TCursor(-2); // Arrow;
2739  UnicodeString MessageStr = "Insufficient memory available to store this image";
2740  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2741  }
2742  else
2743  {
2744  ErrorLog(42, e.Message);
2745  }
2746  }
2747 }
2748 
2749 // ---------------------------------------------------------------------------
2750 
2751 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2752 {
2753  // need to stop clock in case invoke during operation
2754  try
2755  {
2756  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2757  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2758  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2759  {
2760  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2761  Utilities->CallLogPop(1696);
2762  return;
2763  }
2764  Screen->Cursor = TCursor(-11); // Hourglass;
2765  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2767  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2768  // format "16/06/2009 20:55:17"
2769  // avoid characters in filename:= / \ : * ? " < > |
2770  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2771  AnsiString ShortName = "";
2772  for(int x = ImageFileName.Length(); x > 0; x--)
2773  {
2774  if(ImageFileName[x] == '\\')
2775  {
2776  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2777  break;
2778  }
2779  }
2780  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2781  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2782  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2783  int HPosMin = Track->GetHLocMin() * 16;
2784  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2785  int VPosMin = Track->GetVLocMin() * 16;
2786  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2787  RailwayImage->Width = HPosMax - HPosMin;
2788  RailwayImage->Height = VPosMax - VPosMin;
2789 
2790  // need to check if there is any text that extends past HPosMax or below VPosMax
2791  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2792  if(!TextHandler->TextVector.empty())
2793  {
2794  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2795  {
2796  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2797  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2798  if(NewWidth > RailwayImage->Width)
2799  {
2800  RailwayImage->Width = NewWidth;
2801  }
2802  if(NewHeight > RailwayImage->Height)
2803  {
2804  RailwayImage->Height = NewHeight;
2805  }
2806  }
2807  }
2808  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2809  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2810  RailwayImage->Canvas->FillRect(Rect);
2811 
2812  // write the grid first so all else on top
2813  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2814  {
2815  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2816  {
2817  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2818  }
2819  }
2820  // write graphics next so text & track overwrite
2821  Track->WriteGraphicsToImage(1, RailwayImage);
2822  // then write text so track overwrites
2823  TextHandler->WriteTextToImage(1, RailwayImage);
2824  Track->WriteTrackToImage(1, RailwayImage);
2825  RailwayImage->SaveToFile(ImageFileName);
2826  delete RailwayImage;
2827  TrainController->BaseTime = TDateTime::CurrentDateTime();
2829  Screen->Cursor = TCursor(-2); // Arrow
2830  Utilities->CallLogPop(1536);
2831  }
2832  catch(const Exception &e)
2833  {
2834  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2835  {
2836  Screen->Cursor = TCursor(-2); // Arrow;
2837  UnicodeString MessageStr = "Insufficient memory available to store this image";
2838  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2839  }
2840  else
2841  {
2842  ErrorLog(43, e.Message);
2843  }
2844  }
2845 }
2846 // ---------------------------------------------------------------------------
2847 
2848 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2849 {
2850  // need to stop clock in case invoke during operation
2851  try
2852  {
2853  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2854  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2855  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2856  {
2857  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2858  Utilities->CallLogPop(1697);
2859  return;
2860  }
2861  Screen->Cursor = TCursor(-11); // Hourglass;
2862  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2864  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2865  // format "16/06/2009 20:55:17"
2866  // avoid characters in filename:= / \ : * ? " < > |
2867  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2868  AnsiString ShortName = "";
2869  for(int x = ImageFileName.Length(); x > 0; x--)
2870  {
2871  if(ImageFileName[x] == '\\')
2872  {
2873  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2874  break;
2875  }
2876  }
2877  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2878  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2879  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2880  int HPosMin = Track->GetHLocMin() * 16;
2881  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2882  int VPosMin = Track->GetVLocMin() * 16;
2883  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2884  RailwayImage->Width = HPosMax - HPosMin;
2885  RailwayImage->Height = VPosMax - VPosMin;
2886 
2887  // need to check if there is any text that extends past HPosMax or below VPosMax
2888  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2889  if(!TextHandler->TextVector.empty())
2890  {
2891  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2892  {
2893  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2894  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2895  if(NewWidth > RailwayImage->Width)
2896  {
2897  RailwayImage->Width = NewWidth;
2898  }
2899  if(NewHeight > RailwayImage->Height)
2900  {
2901  RailwayImage->Height = NewHeight;
2902  }
2903  }
2904  }
2905  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2906  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2907  RailwayImage->Canvas->FillRect(Rect);
2908 
2909  // write graphics first so text & track overwrite
2910  Track->WriteGraphicsToImage(2, RailwayImage);
2911  // then write text so track overwrites
2912  TextHandler->WriteTextToImage(2, RailwayImage);
2913  Track->WriteTrackToImage(2, RailwayImage);
2914  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2915  RailwayImage->SaveToFile(ImageFileName);
2916  delete RailwayImage;
2917  TrainController->BaseTime = TDateTime::CurrentDateTime();
2919  Screen->Cursor = TCursor(-2); // Arrow
2920  Utilities->CallLogPop(1566);
2921  }
2922  catch(const Exception &e)
2923  {
2924  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2925  {
2926  Screen->Cursor = TCursor(-2); // Arrow;
2927  UnicodeString MessageStr = "Insufficient memory available to store this image";
2928  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2929  }
2930  else
2931  {
2932  ErrorLog(45, e.Message);
2933  }
2934  }
2935 }
2936 // ---------------------------------------------------------------------------
2937 
2938 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2939 {
2940  // need to stop clock
2941  try
2942  {
2943  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2944  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2945  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2946  {
2947  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2948  Utilities->CallLogPop(1702);
2949  return;
2950  }
2951  Screen->Cursor = TCursor(-11); // Hourglass;
2952  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2954 
2955  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2956  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2957  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2958  // format "16/06/2009 20:55:17"
2959  // avoid characters in filename:= / \ : * ? " < > |
2960  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2961  "; " + TimetableTitle + ".bmp";
2962  AnsiString ShortName = "";
2963  for(int x = ImageFileName.Length(); x > 0; x--)
2964  {
2965  if(ImageFileName[x] == '\\')
2966  {
2967  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2968  break;
2969  }
2970  }
2971  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2972  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2973  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2974  int HPosMin = Track->GetHLocMin() * 16;
2975  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2976  int VPosMin = Track->GetVLocMin() * 16;
2977  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2978  RailwayImage->Width = HPosMax - HPosMin;
2979  RailwayImage->Height = VPosMax - VPosMin;
2980 
2981  // need to check if there is any text that extends past HPosMax or below VPosMax
2982  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2983  if(!TextHandler->TextVector.empty())
2984  {
2985  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2986  {
2987  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2988  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2989  if(NewWidth > RailwayImage->Width)
2990  {
2991  RailwayImage->Width = NewWidth;
2992  }
2993  if(NewHeight > RailwayImage->Height)
2994  {
2995  RailwayImage->Height = NewHeight;
2996  }
2997  }
2998  }
2999  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
3000  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
3001  RailwayImage->Canvas->FillRect(Rect);
3002 
3003  // write graphics first so text & track overwrite
3004  Track->WriteGraphicsToImage(3, RailwayImage);
3005  // then write text so track overwrites
3006  TextHandler->WriteTextToImage(3, RailwayImage);
3007  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
3008  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
3009 // add any locked route markers
3010  if(!AllRoutes->LockedRouteVector.empty())
3011  {
3012  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
3013  {
3014  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
3015  int x = Route.PrefDirSize() - 1;
3016  bool BreakFlag = false;
3017  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
3018  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
3019  {
3020  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3021  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3022  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
3023  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
3024  {
3025  BreakFlag = true;
3026  break; // train removed earlier element from route so stop here
3027  }
3028  x--;
3029  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
3030  }
3031  if(!BreakFlag)
3032  {
3033  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
3034  {
3035  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3036  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3037  }
3038  }
3039  }
3040  }
3041  TrainController->WriteTrainsToImage(0, RailwayImage);
3042  RailwayImage->SaveToFile(ImageFileName);
3043  delete RailwayImage;
3044  TrainController->BaseTime = TDateTime::CurrentDateTime();
3046  Screen->Cursor = TCursor(-2); // Arrow
3047  Utilities->CallLogPop(1703);
3048  }
3049  catch(const Exception &e)
3050  {
3051  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
3052  {
3053  Screen->Cursor = TCursor(-2); // Arrow;
3054  UnicodeString MessageStr = "Insufficient memory available to store this image";
3055  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
3056  }
3057  else
3058  {
3059  ErrorLog(113, e.Message); // NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
3060  }
3061  }
3062 }
3063 
3064 // ---------------------------------------------------------------------------
3065 
3066 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
3067 {
3068 //
3069  try
3070  {
3071  TrainController->LogEvent("SaveHeaderMenu1Click");
3072  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
3073  if(Sender == SaveSessionButton)
3074  {
3075  SaveSessionFlag = true;
3076  }
3077  else if(SavedFileName == "") // use 'Save As' function
3078  {
3079  SaveAsSubroutine(1);
3080  }
3081  else // ordinary save
3082  {
3083  Screen->Cursor = TCursor(-11); // Hourglass;
3084  std::ofstream VecFile(SavedFileName.c_str());
3085  if(!(VecFile.fail()))
3086  {
3090  // save track elements
3091  if(Track->UserGraphicVector.empty())
3092  {
3093  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
3094  }
3095  else
3096  {
3097  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
3098  }
3099  // save text elements
3100  TextHandler->SaveText(5, VecFile);
3101  // save PrefDir elements
3102  EveryPrefDir->SavePrefDirVector(8, VecFile);
3103  if(!Track->UserGraphicVector.empty())
3104  {
3105  // save user graphics
3106  Track->SaveUserGraphics(1, VecFile);
3107  }
3108  FileChangedFlag = false;
3109  VecFile.close();
3110  }
3111  else
3112  {
3113  ShowMessage("Railway failed to save - can't open file");
3114  }
3115  Screen->Cursor = TCursor(-2); // Arrow
3116  }
3117  Utilities->CallLogPop(1552);
3118  }
3119  catch(const Exception &e)
3120  {
3121  ErrorLog(44, e.Message);
3122  }
3123 }
3124 
3125 // ---------------------------------------------------------------------------
3126 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
3127 {
3128  try
3129  {
3130  TrainController->LogEvent("LoadSessionMenuItemClick");
3131  LoadSessionFlag = true; // load session within ClockTimer2
3132  }
3133  catch(const Exception &e)
3134  {
3135  ErrorLog(136, e.Message);
3136  }
3137 }
3138 
3139 // ---------------------------------------------------------------------------
3140 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
3141 {
3142  try
3143  {
3144  TrainController->LogEvent("ClearAllMenuItemClick");
3145  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
3146  if(ClearEverything(2))
3147  {
3148  ;
3149  } // no change in action on result
3150 
3151  Level1Mode = BaseMode;
3152  SetLevel1Mode(126);
3153  Utilities->CallLogPop(1179);
3154  }
3155  catch(const Exception &e)
3156  {
3157  ErrorLog(137, e.Message);
3158  }
3159 }
3160 
3161 // ---------------------------------------------------------------------------
3162 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
3163 {
3164  // no need to stop clock as can't be called when railway operating
3165  try
3166  {
3167  TrainController->LogEvent("ExportTTMenuItemClick");
3168  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
3169  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
3170  {
3171  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
3172  Utilities->CallLogPop(1699);
3173  return;
3174  }
3175 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
3176 // the message instead, but reset here afterwards
3177  // no need to stop clock as can't select this if operating
3179  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
3180  Utilities->CallLogPop(1573);
3181  }
3182  catch(const Exception &e)
3183  {
3184  ErrorLog(138, e.Message);
3185  }
3186 }
3187 // ---------------------------------------------------------------------------
3188 // Timetable editing functions
3189 
3190 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
3191  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
3192  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
3193  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
3194  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
3195 
3196  CR & LF review:
3197  These cause problems by the way that different subroutines handle them.
3198 
3199  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
3200 
3201  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
3202  (a) n-1 characters are stored + '\0' after the n-1 characters;
3203  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
3204  precedes the CRLF in the stream; and
3205  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
3206  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
3207 
3208  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
3209  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
3210 
3211 */
3212 // ---------------------------------------------------------------------------
3213 
3214 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
3215 {
3216  try
3217  {
3218  TrainController->LogEvent("CreateTimetableMenuItemClick");
3219  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
3220  CreateEditTTFileName = "";
3221  TimetableEditVector.clear();
3222  TimetableEditPanel->Visible = true;
3223  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3224  HighlightPanel->Visible = false;
3225  TimetablePanel->Visible = true;
3226  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3227  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3228  OneEntryTimetableMemo->Clear();
3229  AllEntriesTTListBox->Clear();
3230  TTStartTimeBox->Text = "";
3231  AddSubMinsBox->Text = "";
3233  LocationNameComboBox->Clear();
3234  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
3235  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3236  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3237  TimetableChangedFlag = false;
3238  TimetableValidFlag = false;
3239  TTEntryChangedFlag = false;
3241  AZOrderButton->Caption = AnsiString("A-Z Order");
3242  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3243  CopiedEntryFlag = false;
3244  NewEntryInPreparationFlag = false;
3245  CopiedEntryStr = "";
3246  TEVPtr = 0;
3248  TTFirstServicePtr = 0;
3249  TTLastServicePtr = 0; // all set to null to begin with
3250 
3251 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3252  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3254  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3255  {
3256  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3257  == Track->ContinuationNameMap.end())
3258  {
3259  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3260  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3261  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3262  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3263  }
3264  }
3266  if(!(Track->ActiveTrackElementNameMap.empty()))
3267  {
3268  LocationNameComboBox->Text = "Location names";
3269 // new version at beta v0.2b
3271  ATENIT++)
3272  {
3273  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3274  // continuations as well as other track will be included - earlier version
3275  // would have excluded them
3276  }
3277 
3278 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3279  locations
3280  TStringList *StringList = new TStringList;
3281  StringList->Clear();//probably already empty but help file doesn't say so
3282  StringList->Sorted = false;//for now
3283  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3284  {
3285  NewKey = LNMIT->first;
3286  if(OldKey != NewKey)//only add new values
3287  {
3288  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3289  {
3290  StringList->Add(NewKey);
3291  OldKey = NewKey;
3292  }
3293  }
3294  }
3295  StringList->Sort();
3296  for(int x=0;x<StringList->Count;x++)
3297  {
3298  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3299  }
3300  delete StringList;
3301 */
3302  }
3303  else
3304  {
3305  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3306  }
3308  SetLevel1Mode(82);
3309  Utilities->CallLogPop(1595);
3310  }
3311  catch(const Exception &e)
3312  {
3313  ErrorLog(47, e.Message);
3314  }
3315 }
3316 
3317 // ---------------------------------------------------------------------------
3318 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3319 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3320  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3321 */
3322 {
3323  try
3324  {
3325  TrainController->LogEvent("EditTimetableMenuItemClick");
3326  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3327  SigImagePanel->Visible = false; // stop panel showing while waiting for name entry
3328  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3329  CreateEditTTFileName = "";
3330  TimetableEditVector.clear();
3331  TimetableEditPanel->Visible = true;
3332  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3333  HighlightPanel->Visible = false;
3334  TimetablePanel->Visible = true;
3335  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3336  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3337  OneEntryTimetableMemo->Clear();
3338  AllEntriesTTListBox->Clear();
3339  TTStartTimeBox->Text = "";
3340  AddSubMinsBox->Text = "";
3342  LocationNameComboBox->Clear();
3343  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3344  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3345  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3346  TEVPtr = 0;
3348  TTFirstServicePtr = 0;
3349  TTLastServicePtr = 0; // all set to null to begin with
3350  if(TimetableDialog->Execute())
3351  {
3352  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
3353  {
3354  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3355  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3356  }
3357  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3358  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3359  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3360  if(TTBLFile.is_open())
3361  {
3362  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3363  char c;
3364  while(!TTBLFile.eof())
3365  {
3366  TTBLFile.get(c);
3367  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3368  {
3369  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3370  TTBLFile.close();
3371  Utilities->CallLogPop(1612);
3372  return;
3373  }
3374  }
3375  TTBLFile.close();
3376  }
3377  else
3378  {
3379  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3380  Utilities->CallLogPop(1597);
3381  return;
3382  }
3383  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3384  Delay(4, 100); // 100mSec delay between closing & re-opening file
3385  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3386  if(TTBLFile.is_open())
3387  {
3388  TTBLFile.clear(); // to clear eofbit from last read
3389  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3390  TimetableChangedFlag = false;
3391  TimetableValidFlag = false;
3392  TTEntryChangedFlag = false;
3394  AZOrderButton->Caption = AnsiString("A-Z Order");
3395  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3396  NewEntryInPreparationFlag = false;
3397  CopiedEntryStr = "";
3398  CopiedEntryFlag = false;
3399 // CreateEditTTFileName = TimetableDialog->FileName;
3400  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3401  {
3402  if(CreateEditTTFileName[x] == '\\')
3403  {
3404  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3405  break;
3406  }
3407  }
3408  char *TimetableEntryString = new char[10000];
3409  while(true)
3410  {
3411  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3412  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3413  {
3414  // may still have eof even if read a line, and
3415  // if so need to process it
3416  break;
3417  }
3418  AnsiString OneLine(TimetableEntryString);
3419  TimetableEditVector.push_back(OneLine);
3420  }
3421  TTBLFile.close();
3422  delete[]TimetableEntryString;
3423  // here with TimetableEditVector compiled
3424  }
3425  else
3426  {
3427  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3428  Utilities->CallLogPop(1654);
3429  return;
3430  }
3431  }
3432  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3433  {
3434  CreateEditTTFileName = "";
3435 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3436  CreateEditTTTitle = ""; // as above
3437  Level1Mode = BaseMode;
3438  SetLevel1Mode(132);
3439  Utilities->CallLogPop(1633);
3440  return;
3441  }
3443  if(TimetableEditVector.empty())
3444  {
3446  SetLevel1Mode(89);
3447  Utilities->CallLogPop(1614);
3448  return;
3449  }
3450 // all now set where can be
3452 
3453 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3454  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3456  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3457  {
3458  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3459  == Track->ContinuationNameMap.end())
3460  {
3461  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3462  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3463  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3464  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3465  }
3466  }
3468  if(!(Track->ActiveTrackElementNameMap.empty()))
3469  {
3470  LocationNameComboBox->Text = "Location names";
3471 // new version for beta v0.2b
3473  ATENIT++)
3474  {
3475  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3476  // continuations as well as other track will be included - earlier version
3477  // would have excluded them
3478  }
3479  }
3480  else
3481  {
3482  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3483  }
3485  SetLevel1Mode(83);
3486  Utilities->CallLogPop(1596);
3487  }
3488  catch(const Exception &e)
3489  {
3490  ErrorLog(48, e.Message);
3491  }
3492 }
3493 // ---------------------------------------------------------------------------
3494 
3495 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3496 {
3497  try
3498  {
3499  TrainController->LogEvent("ShowHideTTButtonClick");
3500  if(TimetableEditPanel->Visible)
3501  {
3502  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3503  TimetableEditPanel->Visible = false;
3504  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
3505  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3506 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3507  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3508  }
3509  else
3510  {
3511  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3512  TimetableEditPanel->Visible = true;
3513  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3514  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3516  SetLevel1Mode(124);
3517  }
3518  }
3519  catch(const Exception &e)
3520  {
3521  ErrorLog(139, e.Message);
3522  }
3523 }
3524 // ---------------------------------------------------------------------------
3525 
3526 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3527 {
3528  try
3529  {
3530  TrainController->LogEvent("NextTTEntryButtonClick");
3531  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3532  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3533  {
3534  Utilities->CallLogPop(1683);
3535  return;
3536  }
3537  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3538  {
3540  }
3541  TTEntryChangedFlag = false;
3542  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3543  // position changing in AllEntriesTTListBox
3545  SetLevel1Mode(85);
3546  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3547  {
3549  }
3550  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3551  {
3552  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3553  }
3554  else
3555  {
3556  AllEntriesTTListBox->TopIndex = TopPos;
3557  }
3558  Utilities->CallLogPop(1605);
3559  }
3560  catch(const Exception &e)
3561  {
3562  ErrorLog(50, e.Message);
3563  }
3564 }
3565 
3566 // ---------------------------------------------------------------------------
3567 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3568 {
3569  try
3570  {
3571  TrainController->LogEvent("PreviousTTEntryButtonClick");
3572  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3573  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3574  {
3575  Utilities->CallLogPop(1684);
3576  return;
3577  }
3579  {
3581  }
3582  TTEntryChangedFlag = false;
3583  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3584  // position changing in AllEntriesTTListBox
3586  SetLevel1Mode(86);
3587  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3588  {
3590  }
3591  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3592  {
3593  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3594  }
3595  else
3596  {
3597  AllEntriesTTListBox->TopIndex = TopPos;
3598  }
3599  Utilities->CallLogPop(1607);
3600  }
3601  catch(const Exception &e)
3602  {
3603  ErrorLog(51, e.Message);
3604  }
3605 }
3606 
3607 // ---------------------------------------------------------------------------
3608 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3609 {
3610  try
3611  {
3612  TrainController->LogEvent("NewTTEntryButtonClick");
3613  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3614  OneEntryTimetableMemo->Clear();
3615  OneEntryTimetableMemo->SetFocus();
3618  SetLevel1Mode(103);
3619  Utilities->CallLogPop(1615);
3620  }
3621  catch(const Exception &e)
3622  {
3623  ErrorLog(52, e.Message);
3624  }
3625 }
3626 // ---------------------------------------------------------------------------
3627 
3628 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3629 {
3630  try
3631  {
3632  TrainController->LogEvent("AddMinsButtonClick");
3633  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3634  bool ValidFlag = true;
3635  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3636  {
3637  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3638  {
3639  ValidFlag = false;
3640  break;
3641  }
3642  }
3643  if(ValidFlag)
3644  {
3645  if(AddSubMinsBox->Text.ToInt() == 0)
3646  {
3647  ValidFlag = false;
3648  }
3649  }
3650  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3651  {
3652  Utilities->CallLogPop(1649);
3653  return;
3654  }
3655  TDateTime DummyTime;
3656  int AddMins = AddSubMinsBox->Text.ToInt();
3657  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3658  {
3659  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3660  {
3661  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3662  {
3663  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3664  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3665  Mins += AddMins;
3666  while(Mins >= 60)
3667  {
3668  Mins -= 60;
3669  Hrs++;
3670  }
3671  if(Hrs > 95)
3672  {
3673  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3674  Utilities->CallLogPop(1650);
3675  return;
3676  }
3677  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3678  if(Mins < 10)
3679  {
3680  MinsStr = "0" + MinsStr;
3681  }
3682  if(Hrs < 10)
3683  {
3684  HrsStr = "0" + HrsStr;
3685  }
3686  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3687  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3688  NewString += HrsStr + ':' + MinsStr;
3689  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3690  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3691  }
3692  }
3693  }
3694 
3695  OneEntryTimetableMemo->HideSelection = true;
3696  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3697  OneEntryTimetableMemo->SelLength = 0;
3698  TimetableValidFlag = false;
3699  TimetableChangedFlag = true;
3700  TTEntryChangedFlag = true;
3702  SetLevel1Mode(91);
3703  Utilities->CallLogPop(1617);
3704  }
3705  catch(const Exception &e)
3706  {
3707  ErrorLog(54, e.Message);
3708  }
3709 }
3710 // ---------------------------------------------------------------------------
3711 
3712 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3713 {
3714  try
3715  {
3716  TrainController->LogEvent("SubMinsButtonClick");
3717  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3718  bool ValidFlag = true;
3719  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3720  {
3721  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3722  {
3723  ValidFlag = false;
3724  break;
3725  }
3726  }
3727  if(ValidFlag)
3728  {
3729  if(AddSubMinsBox->Text.ToInt() == 0)
3730  {
3731  ValidFlag = false;
3732  }
3733  }
3734  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3735  {
3736  Utilities->CallLogPop(1659);
3737  return;
3738  }
3739  TDateTime DummyTime;
3740  int SubMins = AddSubMinsBox->Text.ToInt();
3741  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3742  {
3743  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3744  {
3745  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3746  {
3747  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3748  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3749  Mins -= SubMins;
3750  while(Mins < 0)
3751  {
3752  Mins += 60;
3753  Hrs--;
3754  }
3755  if(Hrs < 0)
3756  {
3757  ShowMessage("One or more times are now before 00:00, this is not permitted");
3758  Utilities->CallLogPop(1660);
3759  return;
3760  }
3761  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3762  if(Mins < 10)
3763  {
3764  MinsStr = "0" + MinsStr;
3765  }
3766  if(Hrs < 10)
3767  {
3768  HrsStr = "0" + HrsStr;
3769  }
3770  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3771  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3772  NewString += HrsStr + ':' + MinsStr;
3773  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3774  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3775  }
3776  }
3777  }
3778  OneEntryTimetableMemo->HideSelection = true;
3779  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3780  OneEntryTimetableMemo->SelLength = 0;
3781  TimetableValidFlag = false;
3782  TimetableChangedFlag = true;
3783  TTEntryChangedFlag = true;
3785  SetLevel1Mode(92);
3786  Utilities->CallLogPop(1618);
3787  }
3788  catch(const Exception &e)
3789  {
3790  ErrorLog(55, e.Message);
3791  }
3792 }
3793 // ---------------------------------------------------------------------------
3794 
3795 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3796 {
3797  try
3798  {
3799  TrainController->LogEvent("CopyTTEntryButtonClick");
3800  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3801  if(TTCurrentEntryPtr == 0)
3802  {
3803  Utilities->CallLogPop(1636);
3804  return;
3805  }
3807  CopiedEntryFlag = true;
3808  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3809  // position changing in AllEntriesTTListBox
3811  SetLevel1Mode(93);
3812  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3813  {
3815  }
3816  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3817  {
3818  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3819  }
3820  else
3821  {
3822  AllEntriesTTListBox->TopIndex = TopPos;
3823  }
3824  Utilities->CallLogPop(1619);
3825  }
3826  catch(const Exception &e)
3827  {
3828  ErrorLog(56, e.Message);
3829  }
3830 }
3831 // ---------------------------------------------------------------------------
3832 
3833 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3834 {
3835  try
3836  {
3837  TrainController->LogEvent("CutTTEntryButtonClick");
3838  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3839  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3840  {
3841  Utilities->CallLogPop(1674);
3842  return;
3843  }
3845  CopiedEntryFlag = true;
3846  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3847  // so use the position in the vector
3849 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3850 // pick up the start time if there is one
3851  TimetableChangedFlag = true;
3852  TimetableValidFlag = false;
3853  TTEntryChangedFlag = false;
3854  TEVPtr = 0;
3856  TTFirstServicePtr = 0;
3857  TTLastServicePtr = 0; // all set to null to begin with
3858  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3859  // position changing in AllEntriesTTListBox
3860  AllEntriesTTListBox->Clear();
3862  if(TimetableEditVector.empty())
3863  {
3865  SetLevel1Mode(109);
3866  Utilities->CallLogPop(1777);
3867  return;
3868  }
3869 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed after v2.4.3
3870 // but vector pointers unreliable after an erase, so use the position in the vector
3871  if(OldVectorPos == 0)
3872  {
3874  }
3875  else
3876  {
3877  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3878  }
3879  if(TTCurrentEntryPtr == 0)
3880  {
3881  OneEntryTimetableMemo->Clear();
3882  }
3884  SetLevel1Mode(115);
3885  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3886  {
3888  }
3889  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3890  {
3891  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3892  }
3893  else
3894  {
3895  AllEntriesTTListBox->TopIndex = TopPos;
3896  }
3897  Utilities->CallLogPop(1676);
3898  }
3899  catch(const Exception &e)
3900  {
3901  ErrorLog(111, e.Message);
3902  }
3903 }
3904 
3905 // ---------------------------------------------------------------------------
3906 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3907 {
3908  try
3909  {
3910  TrainController->LogEvent("PasteTTEntryButtonClick");
3911  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3912  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3913  {
3914  Utilities->CallLogPop(1637);
3915  return;
3916  }
3917  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3918  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3919  // after the current Entry - may be at the end
3920  TimetableChangedFlag = true;
3921  TimetableValidFlag = false;
3922  TTEntryChangedFlag = false;
3923  TEVPtr = 0;
3925  TTFirstServicePtr = 0;
3926  TTLastServicePtr = 0; // all set to null to begin with
3927  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3928  // position changing in AllEntriesTTListBox
3929  AllEntriesTTListBox->Clear();
3931  if(TimetableEditVector.empty())
3932  {
3934  SetLevel1Mode(110);
3935  Utilities->CallLogPop(1778);
3936  return;
3937  }
3938 // restore TTCurrentEntryPtr
3939  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3940  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3941 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3943  SetLevel1Mode(94);
3944  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3945  {
3947  }
3948  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3949  {
3950  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3951  }
3952  else
3953  {
3954  AllEntriesTTListBox->TopIndex = TopPos;
3955  }
3956  Utilities->CallLogPop(1620);
3957  }
3958  catch(const Exception &e)
3959  {
3960  ErrorLog(57, e.Message);
3961  }
3962 }
3963 // ---------------------------------------------------------------------------
3964 
3965 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3966 {
3967  try
3968  {
3969  TrainController->LogEvent("DeleteTTEntryButtonClick");
3970  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3971  if(TTCurrentEntryPtr == 0)
3972  {
3973  Utilities->CallLogPop(1645);
3974  return;
3975  }
3976  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3977  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3978  if(button == IDNO)
3979  {
3980  Utilities->CallLogPop(1663);
3981  return;
3982  }
3983  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3984  // so use the position in the vector
3986 
3987 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3988 // pick up the start time if there is one
3989  TimetableChangedFlag = true;
3990  TimetableValidFlag = false;
3991  TTEntryChangedFlag = false;
3992  TEVPtr = 0;
3994  TTFirstServicePtr = 0;
3995  TTLastServicePtr = 0; // all set to null to begin with
3996  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3997  // position changing in AllEntriesTTListBox
3998  AllEntriesTTListBox->Clear();
4000  if(TimetableEditVector.empty())
4001  {
4003  SetLevel1Mode(111);
4004  Utilities->CallLogPop(1779);
4005  return;
4006  }
4007 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
4008 // but vector pointers unreliable after an erase, so use the position in the vector
4009  if(OldVectorPos == 0)
4010  {
4012  }
4013  else
4014  {
4015  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
4016  }
4017  if(TTCurrentEntryPtr == 0)
4018  {
4019  OneEntryTimetableMemo->Clear();
4020  }
4022  SetLevel1Mode(95);
4023  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4024  {
4026  }
4027  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4028  {
4029  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4030  }
4031  else
4032  {
4033  AllEntriesTTListBox->TopIndex = TopPos;
4034  }
4035  Utilities->CallLogPop(1621);
4036  }
4037  catch(const Exception &e)
4038  {
4039  ErrorLog(58, e.Message);
4040  }
4041 }
4042 // ---------------------------------------------------------------------------
4043 
4044 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
4045 {
4046  try
4047  {
4048  TrainController->LogEvent("SaveTTEntryButtonClick");
4049  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
4050 /* allow blank lines to be saved
4051  AnsiString ContentStr = OneEntryTimetableMemo->Text;
4052  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
4053  {
4054  Utilities->CallLogPop(1679);
4055  return;
4056  }
4057 */
4058  AnsiString TempStr = "";
4059  bool ActiveLine = false;
4060  if(TTCurrentEntryPtr > 0)
4061  {
4062  if(*TTCurrentEntryPtr != "")
4063  {
4065  {
4066  ActiveLine = true;
4067  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
4068  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
4069  {
4070  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
4071  {
4072  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
4073  }
4074  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
4075  {
4076  TempStr += ',';
4077  }
4078  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
4079  // ends the timetable
4080  }
4081  // strip any excess commas from the end
4082  if(TempStr != "")
4083  {
4084  while(TempStr[TempStr.Length()] == ',')
4085  {
4086  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
4087  if(TempStr == "")
4088  {
4089  break;
4090  }
4091  }
4092  }
4093  }
4094  }
4095  }
4096  if(!ActiveLine)
4097  {
4098  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
4099  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
4100  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
4101  // and before a blank line or end of file, so the syntax check will work OK
4102  }
4103  if(AZOrderButton->Caption == AnsiString("Original Order"))
4104  {
4106  }
4107  TimetableValidFlag = false;
4108  TimetableChangedFlag = true;
4109  TTEntryChangedFlag = false;
4110  int TopPos;
4111  if(TTCurrentEntryPtr == 0)
4112  {
4114  }
4116  {
4117  (*TTCurrentEntryPtr) = TempStr;
4118  // need to reset the AllEntriesTTListBox in case the headcode has changed
4119  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4120  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4121  // position changing in AllEntriesTTListBox
4122  AllEntriesTTListBox->Clear();
4124  if(TimetableEditVector.empty())
4125  {
4127  SetLevel1Mode(112);
4128  Utilities->CallLogPop(1780);
4129  return;
4130  }
4131  // restore TTCurrentEntryPtr
4132  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4133  }
4134  else
4135  {
4136  NewEntryInPreparationFlag = false;
4137  if(TTCurrentEntryPtr != 0)
4138  {
4139  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4140  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
4141  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4143  }
4144  else
4145  {
4146  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
4148  }
4149  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
4150  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4151  // position changing in AllEntriesTTListBox
4152  AllEntriesTTListBox->Clear();
4154  if(TimetableEditVector.empty())
4155  {
4157  SetLevel1Mode(113);
4158  Utilities->CallLogPop(1781);
4159  return;
4160  }
4161 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4162  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4163  {
4165  }
4166  else
4167  {
4168  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4169  }
4170  }
4172  SetLevel1Mode(96);
4173  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4174  {
4176  }
4177  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4178  {
4179  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4180  }
4181  else
4182  {
4183  AllEntriesTTListBox->TopIndex = TopPos;
4184  }
4185  Utilities->CallLogPop(1622);
4186  }
4187  catch(const Exception &e)
4188  {
4189  ErrorLog(59, e.Message);
4190  }
4191 }
4192 // ---------------------------------------------------------------------------
4193 
4194 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
4195 {
4196  try
4197  {
4198  TrainController->LogEvent("SaveTTButtonClick");
4199  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
4200  if(TimetableEditVector.empty())
4201  {
4202  ShowMessage("Timetable is empty, can't save an empty timetable");
4203  Utilities->CallLogPop(1685);
4204  return;
4205  }
4206  std::ofstream TTBLFile;
4207  if(CreateEditTTFileName != "")
4208  {
4209  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4210  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4211  }
4212  else
4213  {
4214  if(SaveTTDialog->Execute())
4215  {
4216  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4217  {
4218  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4219  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4220  }
4221  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
4222  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
4223  {
4224  if(CreateEditTTFileName[x] == '\\')
4225  {
4226  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4227  break;
4228  }
4229  }
4230  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4231  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4232  }
4233  else // cancelled dialog
4234  {
4236  SetLevel1Mode(137);
4237  Utilities->CallLogPop(2205);
4238  return;
4239  }
4240  }
4241  if(TTBLFile.is_open())
4242  {
4243  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4244  {
4245  TTBLFile << (*TEVPtr).c_str() << '\0';
4246  }
4247  TimetableChangedFlag = false;
4248  TTBLFile.close();
4249  }
4250  else
4251  {
4252  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4253  }
4255  SetLevel1Mode(97);
4256  Utilities->CallLogPop(1623);
4257  }
4258  catch(const Exception &e)
4259  {
4260  ErrorLog(60, e.Message);
4261  }
4262 }
4263 // ---------------------------------------------------------------------------
4264 
4265 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
4266 {
4267  try
4268  {
4269  TrainController->LogEvent("SaveTTAsButtonClick");
4270  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4271  if(TimetableEditVector.empty())
4272  {
4273  ShowMessage("Timetable is empty, can't save an empty timetable");
4274  Utilities->CallLogPop(1686);
4275  return;
4276  }
4277  std::ofstream TTBLFile;
4278  if(SaveTTDialog->Execute())
4279  {
4280  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4281  {
4282  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4283  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4284  }
4285  CreateEditTTFileName = SaveTTDialog->FileName;
4286  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4287  {
4288  if(SaveTTDialog->FileName[x] == '\\')
4289  {
4290  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4291  break;
4292  }
4293  }
4294  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4295  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4296  }
4297  else // cancelled dialog
4298  {
4300  SetLevel1Mode(138);
4301  Utilities->CallLogPop(2206);
4302  return;
4303  }
4304  if(TTBLFile.is_open())
4305  {
4306  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4307  {
4308  TTBLFile << (*TEVPtr).c_str() << '\0';
4309  }
4310  TimetableChangedFlag = false;
4311  TTBLFile.close();
4312  }
4313  else
4314  {
4315  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4316  }
4318  SetLevel1Mode(117);
4319  Utilities->CallLogPop(1667);
4320  }
4321  catch(const Exception &e)
4322  {
4323  ErrorLog(108, e.Message);
4324  }
4325 }
4326 // ---------------------------------------------------------------------------
4327 
4328 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4329 {
4330  try
4331  {
4332  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4333  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4334  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4335  bool EndOfFile = false;
4336  bool FinalCallFalse = false;
4337  bool GiveMessagesTrue = true;
4338  bool CheckLocationsExistInRailway = false;
4339  if(RlyFile)
4340  {
4341  CheckLocationsExistInRailway = true;
4342  }
4343 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4344  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4345  // return true for success
4346  {
4347  ShowMessage(
4348  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4349  }
4351  SetLevel1Mode(98);
4352  Utilities->CallLogPop(1624);
4353  }
4354  catch(const Exception &e)
4355  {
4356  ErrorLog(61, e.Message);
4357  }
4358 }
4359 // ---------------------------------------------------------------------------
4360 
4361 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4362 {
4363  try
4364  {
4365  TrainController->LogEvent("ValidateTimetableButtonClick");
4366  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4367  // reset all message flags, stops them being given twice new at v2.4.0
4368  TrainController->SSHigh = false;
4369  TrainController->MRSHigh = false;
4370  TrainController->MRSLow = false;
4371  TrainController->MassHigh = false;
4372  TrainController->BFHigh = false;
4373  TrainController->BFLow = false;
4374  TrainController->PwrHigh = false;
4375  TrainController->SigSHigh = false;
4376  TrainController->SigSLow = false;
4377  if(CreateEditTTFileName == "")
4378  {
4379  Utilities->CallLogPop(1664);
4380  return;
4381  }
4382  bool CheckLocationsExistInRailwayTrue = true;
4383  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4384  {
4385  Screen->Cursor = TCursor(-11); // Hourglass;
4386  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4387  if(TTBLFile.is_open())
4388  {
4389  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4390  {
4391  ShowMessage("Timetable integrity OK");
4392  TimetableValidFlag = true;
4393 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4394  }
4395  ;
4396  }
4397  else
4398  {
4399  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4400  }
4401  Screen->Cursor = TCursor(-2); // Arrow
4402  } // if(TimetableIntegrityCheck
4403  else
4404  {
4405 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4406  }
4408  SetLevel1Mode(99);
4409  Utilities->CallLogPop(1625);
4410  }
4411  catch(const Exception &e)
4412  {
4413  ErrorLog(62, e.Message);
4414  }
4415 }
4416 
4417 // ---------------------------------------------------------------------------
4418 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4419 {
4420  try
4421  {
4422  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4423  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4424  if(TTCurrentEntryPtr == 0)
4425  {
4426  Utilities->CallLogPop(1634);
4427  return;
4428  }
4429  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4430  {
4431  Utilities->CallLogPop(1632);
4432  return;
4433  }
4434  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4435  AnsiString TempStr = *TEVPtr;
4437  *TTCurrentEntryPtr = TempStr;
4439  TimetableChangedFlag = true;
4440  TimetableValidFlag = false;
4441 
4442 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4443  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4444  // position changing in AllEntriesTTListBox
4445  AllEntriesTTListBox->Clear();
4446  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4448 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4449  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4450  {
4452  }
4453  else
4454  {
4455  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4456  }
4458  SetLevel1Mode(100);
4459  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4460  {
4462  }
4463  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4464  {
4465  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4466  }
4467  else
4468  {
4469  AllEntriesTTListBox->TopIndex = TopPos;
4470  }
4471  Utilities->CallLogPop(1626);
4472  }
4473  catch(const Exception &e)
4474  {
4475  ErrorLog(63, e.Message);
4476  }
4477 }
4478 // ---------------------------------------------------------------------------
4479 
4480 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4481 {
4482  try
4483  {
4484  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4485  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4486  if(TTCurrentEntryPtr == 0)
4487  {
4488  Utilities->CallLogPop(1635);
4489  return;
4490  }
4491  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4492  {
4493  Utilities->CallLogPop(1678);
4494  return;
4495  }
4496  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4497  AnsiString TempStr = *TEVPtr;
4499  *TTCurrentEntryPtr = TempStr;
4501  TimetableChangedFlag = true;
4502  TimetableValidFlag = false;
4503 
4504 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4505  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4506  // position changing in AllEntriesTTListBox
4507  AllEntriesTTListBox->Clear();
4508  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4510 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4511  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4512  {
4514  }
4515  else
4516  {
4517  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4518  }
4520  SetLevel1Mode(101);
4521  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4522  {
4524  }
4525  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4526  {
4527  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4528  }
4529  else
4530  {
4531  AllEntriesTTListBox->TopIndex = TopPos;
4532  }
4533  Utilities->CallLogPop(1627);
4534  }
4535  catch(const Exception &e)
4536  {
4537  ErrorLog(64, e.Message);
4538  }
4539 }
4540 
4541 // ---------------------------------------------------------------------------
4542 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4543 {
4544  try
4545  {
4546  TrainController->LogEvent("CancelTTActionButtonClick");
4547  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4548  TTEntryChangedFlag = false;
4550  {
4551  NewEntryInPreparationFlag = false;
4552  OneEntryTimetableMemo->Clear();
4553  }
4554  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4555  // position changing in AllEntriesTTListBox
4557  SetLevel1Mode(102);
4558  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4559  {
4561  }
4562  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4563  {
4564  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4565  }
4566  else
4567  {
4568  AllEntriesTTListBox->TopIndex = TopPos;
4569  }
4570  Utilities->CallLogPop(1630);
4571  }
4572  catch(const Exception &e)
4573  {
4574  ErrorLog(102, e.Message);
4575  }
4576 }
4577 
4578 // ---------------------------------------------------------------------------
4579 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4580 {
4581  try
4582  {
4583  TrainController->LogEvent("RestoreTTButtonClick");
4584  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4586  {
4587  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4588  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4589  if(button == IDNO)
4590  {
4591  Utilities->CallLogPop(1651);
4592  return;
4593  }
4594  }
4595  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4596  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4597  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4598  if(TTBLFile.is_open())
4599  {
4600  TimetableChangedFlag = false;
4601  TimetableValidFlag = false;
4602  TTEntryChangedFlag = false;
4603  NewEntryInPreparationFlag = false;
4604  CopiedEntryFlag = false;
4605  CopiedEntryStr = "";
4606  TimetableEditVector.clear();
4607  OneEntryTimetableMemo->Clear();
4608  AllEntriesTTListBox->Clear();
4609  TTStartTimeBox->Text = "";
4610  AddSubMinsBox->Text = "";
4611  TEVPtr = 0;
4613  TTFirstServicePtr = 0;
4614  TTLastServicePtr = 0; // all set to null to begin with
4615  char *TimetableEntryString = new char[10000];
4616  while(true)
4617  {
4618  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4619  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4620  {
4621  // may still have eof even if read a line, and
4622  // if so need to process it
4623  break;
4624  }
4625  AnsiString OneLine(TimetableEntryString);
4626  TimetableEditVector.push_back(OneLine);
4627  }
4628  TTBLFile.close();
4629  delete[]TimetableEntryString;
4630  // here with TimetableEditVector compiled
4631  }
4632  else
4633  {
4634  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4635  Utilities->CallLogPop(1655);
4636  return;
4637  }
4639  if(TimetableEditVector.empty())
4640  {
4642  SetLevel1Mode(114);
4643  Utilities->CallLogPop(1782);
4644  return;
4645  }
4646 // all now set where can be
4648 // end of repeat from EditTimetableMenuItemClick
4649 
4651  SetLevel1Mode(104);
4652  Utilities->CallLogPop(1652);
4653  }
4654  catch(const Exception &e)
4655  {
4656  ErrorLog(104, e.Message);
4657  }
4658 }
4659 
4660 // ---------------------------------------------------------------------------
4661 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4662 {
4663  try
4664  {
4665  TrainController->LogEvent("ExportTTButtonClick");
4666  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4667  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4668  {
4669  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4670  Utilities->CallLogPop(1698);
4671  return;
4672  }
4673 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4674 // the message instead, but reset here afterwards
4675  AnsiString TTTitle;
4677  {
4678  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4679  {
4680  if(CreateEditTTFileName[x] == '\\')
4681  {
4682  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4683  break;
4684  }
4685  }
4687  }
4688  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4690  SetLevel1Mode(116);
4691  Utilities->CallLogPop(1662);
4692  }
4693  catch(const Exception &e)
4694  {
4695  ErrorLog(107, e.Message);
4696  }
4697 }
4698 
4699 // ---------------------------------------------------------------------------
4700 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4701 {
4702  try
4703  {
4704  TrainController->LogEvent("TTTextButtonClick");
4705  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4706 /*
4707  if(TTStartTimePtr == 0)
4708  {
4709  OneEntryTimetableMemo->Clear();
4710  TTStartTimeBox->SetFocus();
4711  Utilities->CallLogPop(1673);
4712  return;
4713  }
4714 */
4715  int SelPos = OneEntryTimetableMemo->SelStart;
4716  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4717  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4718  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4719  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4720  TTEntryChangedFlag = true;
4721  OneEntryTimetableMemo->SetFocus();
4723  SetLevel1Mode(119);
4724  Utilities->CallLogPop(1672);
4725  }
4726  catch(const Exception &e)
4727  {
4728  ErrorLog(110, e.Message);
4729  }
4730 }
4731 
4732 // ---------------------------------------------------------------------------
4733 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4734 {
4735  try
4736  {
4737  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4738  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4740  {
4741  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4742  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4743  if(button == IDNO)
4744  {
4745  Utilities->CallLogPop(1603);
4746  return;
4747  }
4748  }
4749  TimetableChangedFlag = false;
4750  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4751  // added for Beta v0.2b
4752  CreateEditTTTitle = ""; // as above
4753  ConflictPanel->Visible = false;
4754  Level1Mode = BaseMode;
4755  SetLevel1Mode(84);
4756  Utilities->CallLogPop(1606);
4757  }
4758  catch(const Exception &e)
4759  {
4760  ErrorLog(49, e.Message);
4761  }
4762 }
4763 
4764 // ---------------------------------------------------------------------------
4765 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4766 {
4767  try
4768  {
4769  TrainController->LogEvent("LocationNameComboBoxClick");
4770  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4771  if(TTStartTimePtr != 0)
4772  {
4773  LocationNameComboBox->SelectAll();
4774  int SelPos = OneEntryTimetableMemo->SelStart;
4775  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4776  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4777  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4778  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4779  TTEntryChangedFlag = true;
4780  OneEntryTimetableMemo->SetFocus();
4782  SetLevel1Mode(118);
4783  }
4784  Utilities->CallLogPop(1669);
4785  }
4786  catch(const Exception &e)
4787  {
4788  ErrorLog(109, e.Message);
4789  }
4790 }
4791 
4792 // ---------------------------------------------------------------------------
4793 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4794 {
4795  try
4796  {
4797 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4798  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4800  {
4801  Utilities->CallLogPop(1716);
4802  return;
4803  }
4804  TimetableChangedFlag = true;
4805  TTEntryChangedFlag = true;
4806  TimetableValidFlag = false;
4808  SetLevel1Mode(127);
4809  Utilities->CallLogPop(1629);
4810  }
4811  catch(const Exception &e)
4812  {
4813  ErrorLog(66, e.Message);
4814  }
4815 }
4816 
4817 // ---------------------------------------------------------------------------
4818 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4819 {
4820 // forces a recheck for whether addmins/submins buttons should be enabled
4821  try
4822  {
4823  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4824  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4826  SetLevel1Mode(108);
4827  Utilities->CallLogPop(1658);
4828  }
4829  catch(const Exception &e)
4830  {
4831  ErrorLog(106, e.Message);
4832  }
4833 }
4834 
4835 // ---------------------------------------------------------------------------
4836 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4837 {
4838  try
4839  {
4840  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4842  if(!Track->LocationNameMultiMap.empty())
4843  {
4844  LocationNameComboBox->Text = "Location names";
4845  }
4846  else
4847  {
4848  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4849  }
4850  Utilities->CallLogPop(1677);
4851  }
4852  catch(const Exception &e)
4853  {
4854  ErrorLog(112, e.Message);
4855  }
4856 }
4857 
4858 // ---------------------------------------------------------------------------
4859 
4860 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4861 {
4862 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4863  try
4864  {
4865  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4866  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4867  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4868  {
4869  Utilities->CallLogPop(1687);
4870  return;
4871  }
4872  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4873  {
4874  Utilities->CallLogPop(1688);
4875  return;
4876  }
4877  // find item required - 13 pixels per line of text
4878  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4879  // position changing in AllEntriesTTListBox
4880  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4881  {
4883  }
4884  else
4885  {
4886  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4887  }
4888  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4890 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4891  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4892  {
4894  }
4895  else
4896  {
4897  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4898  }
4900  SetLevel1Mode(120);
4901  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4902  Utilities->CallLogPop(1648);
4903  }
4904  catch(const Exception &e)
4905  {
4906  ErrorLog(103, e.Message);
4907  }
4908 }
4909 
4910 // ---------------------------------------------------------------------------
4911 
4912 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4913 {
4914 // Mouseup rather than Mousedown so shows floating label when over selected train
4915  try
4916  {
4917  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y) + "," + AnsiString(Button)); // button may be right or left
4918  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4919  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4920  {
4921  Utilities->CallLogPop(2087);
4922  return;
4923  }
4925  {
4926  Utilities->CallLogPop(2088);
4927  return;
4928  }
4929  int HPos, VPos, TrainID = -1, TrackVectorPosition = -1;
4930  if(!GetTrainIDOrContinuationPosition(0, X, Y, TrainID, TrackVectorPosition))
4931  {
4932  OAListBoxRightMouseButtonDown = false; // so resets when button over blank area
4933  Utilities->CallLogPop(2260);
4934  return;
4935  }
4936  if(Button == mbLeft) // added at v2.7.0 to keep right button for train information
4937  {
4938  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4939  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4940  // now want to set the offsets to display HPos & VPos in the centre of the screen
4941  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4942  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4943  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4944  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4945  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4946  {
4947  Display->ZoomOutFlag = false;
4949  }
4950  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4951  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4952  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4953  Mouse->CursorPos = CursPos;
4954  }
4955  else // mbRight, reset OAListBoxRightMouseButtonDown
4956  {
4958  }
4959  Utilities->CallLogPop(2090);
4960  }
4961  catch(const Exception &e)
4962  {
4963  ErrorLog(200, e.Message);
4964  }
4965 }
4966 
4967 // ---------------------------------------------------------------------------
4968 
4969 void __fastcall TInterface::OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4970 {
4971  try
4972  {
4973  TrainController->LogEvent("OAListBoxMouseDown," + AnsiString(X) + "," + AnsiString(Y));
4974  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseDown");
4975  if(Button == mbRight)
4976  {
4978  }
4979  Utilities->CallLogPop(2264);
4980  }
4981  catch(const Exception &e)
4982  {
4983  ErrorLog(220, e.Message);
4984  }
4985 }
4986 
4987 // ---------------------------------------------------------------------------
4988 
4989 bool TInterface::GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &TrackVectorPosition)
4990 // returns true if value(s) valid
4991 {
4992  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetTrainIDOrContinuationPosition");
4994  // find item required - 13 pixels per line of text
4995  int TopPos = OAListBox->TopIndex;
4996  int OAIndex;
4997  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
4998  {
4999  Utilities->CallLogPop(2089);
5000  return(false);
5001  }
5002  else
5003  {
5004  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
5005  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
5006  }
5007  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
5008  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
5009  {
5010  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
5011  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
5012  // as notified by Rokas Serys by email on 16/05/20
5013  {
5014  TrainID = TrainIDorTVPos;
5015  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
5016  }
5017  else
5018  {
5019  Utilities->CallLogPop(2155); // if not there then ignore
5020  return(false);
5021  }
5022  }
5023  else // train to enter at a continuation, so value is -TVPos of continuation - 1
5024  {
5025  TrackVectorPosition = -(TrainIDorTVPos + 1);
5026  }
5027  Utilities->CallLogPop(2261);
5028  return(true);
5029 }
5030 
5031 // ---------------------------------------------------------------------------
5032 
5034 {
5035  enum
5036  {
5037  PreStartTime, ActiveSegment, PostEnd
5038  } Segment;
5039  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
5040  AllEntriesTTListBox->Clear();
5041  TEVPtr = 0;
5042  TTStartTimePtr = 0;
5043  TTFirstServicePtr = 0;
5044  TTLastServicePtr = 0; // all set to null to begin with
5045  if(TimetableEditVector.empty())
5046  {
5047  TTCurrentEntryPtr = 0;
5048  Utilities->CallLogPop(1681);
5049  return;
5050  }
5051  Segment = PreStartTime;
5052  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
5053  {
5054  if(Segment == PreStartTime) // looking for the start time
5055  {
5056  TDateTime TempTime; // dummy
5057  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
5058  {
5059  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
5060  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
5061  Segment = ActiveSegment;
5062  continue;
5063  }
5064  else
5065  {
5066  if(*TEVPtr == "")
5067  {
5068  AllEntriesTTListBox->Items->Add("- Blank");
5069  }
5070  else
5071  {
5072  AnsiString CurrentStr = *TEVPtr;
5073  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5074  {
5075  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
5076  for(int x = 1; x < CurrentStr.Length(); x++)
5077  {
5078  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5079  {
5080  CurrentStr = CurrentStr.SubString(1, (x - 1));
5081  }
5082  }
5083  }
5084  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
5085  }
5086  continue;
5087  }
5088  }
5089  if(Segment == ActiveSegment)
5090  {
5091  if(*TEVPtr != "")
5092  {
5093  if((*TEVPtr)[1] != '*')
5094  {
5096  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
5097  // SaveTTEntryButtonClick - see comment in that function
5098  if(TTFirstServicePtr == 0)
5099  {
5101  }
5103  }
5104  AnsiString Entry = *TEVPtr;
5105  if(Entry[1] == '*')
5106  {
5107  Entry = "Comment";
5108  }
5109  else
5110  {
5111  int SCPos = Entry.Pos(';'); // semicolon
5112  int CPos = Entry.Pos(','); // comma
5113  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
5114  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
5115  // description - enter the text up to the comma
5116  // both, semicolon before comma, normal - enter text up to the semicolon
5117  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
5118  // semicolon & no comma - enter text up to the semicolon
5119  if((CPos == 0) && (SCPos == 0))
5120  {
5121  Entry = Entry.SubString(1, 12);
5122  }
5123  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
5124  {
5125  Entry = Entry.SubString(1, CPos - 1);
5126  }
5127  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
5128  {
5129  Entry = Entry.SubString(1, SCPos - 1);
5130  }
5131  else if((CPos > 0) && (SCPos == 0))
5132  {
5133  Entry = Entry.SubString(1, CPos - 1);
5134  }
5135  else
5136  {
5137  Entry = Entry.SubString(1, SCPos - 1);
5138  }
5139  }
5140  AllEntriesTTListBox->Items->Add(Entry);
5141  continue;
5142  }
5143  else
5144  {
5145  Segment = PostEnd;
5146  AllEntriesTTListBox->Items->Add("END (Blank)");
5147  continue;
5148  }
5149  }
5150  if(Segment == PostEnd)
5151  {
5152  if(*TEVPtr == "")
5153  {
5154  AllEntriesTTListBox->Items->Add("+ Blank");
5155  }
5156  else
5157  {
5158  AnsiString CurrentStr = *TEVPtr;
5159  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5160  {
5161  CurrentStr = CurrentStr.SubString(1, 10);
5162  for(int x = 1; x < CurrentStr.Length(); x++)
5163  {
5164  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5165  {
5166  CurrentStr = CurrentStr.SubString(1, (x - 1));
5167  }
5168  }
5169  }
5170  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
5171  }
5172  continue;
5173  }
5174  }
5175  if(TTStartTimePtr == 0)
5176  {
5177  TTStartTimeBox->Text = "";
5178  }
5179  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
5180  Utilities->CallLogPop(1680);
5181 }
5182 // ---------------------------------------------------------------------------
5183 
5184 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
5185 {
5186  try
5187  {
5188  if(TimetableEditVector.empty())
5189  {
5190  return; // should be able to access this if it is but keep in for safety
5191  }
5192  TrainController->LogEvent("AZOrderClick");
5193  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
5194  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
5195  {
5196  TTEVPtr SortStart, SortEnd;
5197  UnicodeString MessageStr =
5198  "If you wish to preserve the original order don't save any changes whilst in alphabetical order.\n\n" "To preserve the original order use alphabetical order to find the service required, click it to display it,"
5199  " then revert to the original order where the same service will be displayed and can be changed.";
5200  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
5203  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
5204  if(TTFirstServicePtr != NULL)
5205  {
5206  SortStart = TTFirstServicePtr;
5207  }
5208  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
5209  if(TTLastServicePtr != NULL)
5210  {
5211  SortEnd = TTLastServicePtr + 1;
5212  }
5213  std::sort(SortStart, SortEnd);
5215  bool CurrentEntryChanged = false;
5216  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5217  {
5218  if(TTSelectedEntry == *x)
5219  {
5220  TTCurrentEntryPtr = x;
5221  CurrentEntryChanged = true;
5222  }
5223  }
5224  if(!CurrentEntryChanged)
5225  {
5227  }
5228  AZOrderButton->Caption = AnsiString("Original Order");
5229  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
5230  }
5231  else
5232  {
5234  {
5235  UnicodeString MessageStr =
5236  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
5237  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
5238  if(button == IDNO)
5239  {
5240  TimetableChangedFlag = true;
5241  TimetableValidFlag = false;
5243  SetLevel1Mode(135);
5244  Utilities->CallLogPop(2166);
5245  return;
5246  }
5247  }
5251  bool CurrentEntryChanged = false;
5252  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5253  {
5254  if(TTSelectedEntry == *x)
5255  {
5256  TTCurrentEntryPtr = x;
5257  CurrentEntryChanged = true;
5258  }
5259  }
5260  if(!CurrentEntryChanged)
5261  {
5263  }
5264  AZOrderButton->Caption = AnsiString("A-Z Order");
5265  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
5266  }
5267  TimetableChangedFlag = true;
5268  TimetableValidFlag = false;
5271  SetLevel1Mode(136);
5272  Utilities->CallLogPop(2165);
5273  }
5274  catch(const Exception &e)
5275  {
5276  ErrorLog(211, e.Message);
5277  }
5278 }
5279 
5280 // ---------------------------------------------------------------------------
5281 
5282 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
5283 {
5284  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
5285  AnsiString OutStr = "";
5286  int x = 1; // AnsiString arrays start at 1
5287 
5288  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
5289  {
5290  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
5291  {
5292  OutStr += ',';
5293  x++;
5294  x++;
5295  }
5296  else
5297  {
5298  OutStr += ConvStr[x];
5299  x++;
5300  }
5301  }
5302  if(x == ConvStr.Length())
5303  {
5304  OutStr += ConvStr[x]; // add the last character
5305 
5306  }
5307 // strip any excess commas from the end
5308  if(OutStr != "")
5309  {
5310  while(OutStr[OutStr.Length()] == ',')
5311  {
5312  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
5313  if(OutStr == "")
5314  {
5315  break; // if consisted of just commas then without this would fail on range error when becomes a null string
5316  }
5317  }
5318  }
5319  ConvStr = OutStr;
5320  if(ConvStr == "")
5321  {
5322  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
5323  }
5324  // when AllCommas will be true
5325  Utilities->CallLogPop(1846);
5326 }
5327 
5328 // ---------------------------------------------------------------------------
5329 
5331 {
5332 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5333  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5334  entries
5335 */
5336  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5337  PreviousTTEntryButton->Enabled = false;
5338  NextTTEntryButton->Enabled = false;
5339  AddMinsButton->Enabled = false;
5340  SubMinsButton->Enabled = false;
5341  CopyTTEntryButton->Enabled = false;
5342  CutTTEntryButton->Enabled = false;
5343  PasteTTEntryButton->Enabled = false;
5344  DeleteTTEntryButton->Enabled = false;
5345  SaveTTEntryButton->Enabled = false;
5346  SaveTTButton->Enabled = false;
5347  SaveTTAsButton->Enabled = false;
5348  ValidateTimetableButton->Enabled = false;
5349  AZOrderButton->Enabled = false;
5350  TTServiceSyntaxCheckButton->Enabled = false;
5351  NewTTEntryButton->Enabled = false;
5352  MoveTTEntryUpButton->Enabled = false;
5353  MoveTTEntryDownButton->Enabled = false;
5354  CancelTTEntryButton->Enabled = false;
5355  RestoreTTButton->Enabled = false;
5356  ExportTTButton->Enabled = false;
5357  ConflictAnalysisButton->Enabled = false;
5358  ExitTTModeButton->Enabled = true;
5359 
5361  {
5362  AZOrderButton->Enabled = true;
5363  }
5365  {
5366  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5367 
5368  }
5369  if(CreateEditTTFileName == "")
5370  {
5371  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5372  }
5373  else
5374  {
5375  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5376  }
5377  if(TTStartTimePtr != 0) // Null means start time not yet set
5378  {
5379  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5380  }
5381 // start time now set & displayed
5382 
5384  {
5385  InfoPanel->Visible = true;
5386  InfoPanel->Caption = "Select option or change entry";
5387  if(RailwayTitle != "")
5388  {
5389  ShowHideTTButton->Enabled = true;
5390  }
5391  else
5392  {
5393  ShowHideTTButton->Enabled = false;
5394  }
5395  ExitTTModeButton->Enabled = true;
5396  AllEntriesTTListBox->Enabled = true;
5397  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5398  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5399  {
5400  bool ValidFlag = true;
5401  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5402  {
5403  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5404  {
5405  ValidFlag = false;
5406  break;
5407  }
5408  }
5409  if(ValidFlag)
5410  {
5411  if(AnsiAddSubText.ToInt() != 0)
5412  {
5413  AddMinsButton->Enabled = true;
5414  SubMinsButton->Enabled = true;
5415  }
5416  }
5417  }
5419  {
5420  RestoreTTButton->Enabled = true;
5421  }
5423  {
5424  // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5425  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5426  ValidateTimetableButton->Enabled = true;
5427  }
5429  {
5430  ExportTTButton->Enabled = true;
5431  ConflictAnalysisButton->Enabled = true;
5432  }
5433  if(TTCurrentEntryPtr != 0)
5434  {
5435  CopyTTEntryButton->Enabled = true;
5436  CutTTEntryButton->Enabled = true;
5437  DeleteTTEntryButton->Enabled = true;
5438  }
5439  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5440  {
5441  SaveTTButton->Enabled = true;
5442  }
5443  if(!TimetableEditVector.empty())
5444  {
5445  SaveTTAsButton->Enabled = true;
5446  }
5448  {
5449  NewTTEntryButton->Enabled = true;
5450  }
5451  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5452  {
5453  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5454  {
5455  NextTTEntryButton->Enabled = true;
5456  MoveTTEntryDownButton->Enabled = true;
5457  }
5459  {
5460  PreviousTTEntryButton->Enabled = true;
5461  MoveTTEntryUpButton->Enabled = true;
5462  }
5463  }
5464  if(TTCurrentEntryPtr > 0)
5465  {
5466  if(*TTCurrentEntryPtr != "")
5467  {
5469  {
5470  TTServiceSyntaxCheckButton->Enabled = true;
5471  }
5472  }
5473  }
5474  if(CopiedEntryFlag)
5475  {
5476  PasteTTEntryButton->Enabled = true;
5477  }
5478  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5479  if(TTCurrentEntryPtr > 0)
5480  {
5481 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5483  {
5484  bool ServiceEntry = true;
5485  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5486  }
5487  else
5488  {
5489  bool ServiceEntry = false;
5490  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5491  }
5492  }
5493  }
5494  else
5495  {
5496  CancelTTEntryButton->Enabled = true;
5497  SaveTTEntryButton->Enabled = true;
5498  ShowHideTTButton->Enabled = false;
5499  ExitTTModeButton->Enabled = false;
5500  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5501  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5502  InfoPanel->Visible = true;
5503  }
5504  Utilities->CallLogPop(1600);
5505 }
5506 
5507 // ---------------------------------------------------------------------------
5508 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5509 {
5510  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5511  AnsiString((short)ServiceEntry));
5512  OneEntryTimetableMemo->Clear();
5513  if(ServiceEntry)
5514  {
5515  TrainController->StripSpaces(1, Data);
5516  while(true)
5517  {
5518  int CommaPos = Data.Pos(',');
5519  if((CommaPos == 0) && (Data != ""))
5520  {
5521  CommaPos = Data.Length() + 1;
5522  }
5523  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5524  if(Data.Length() <= CommaPos)
5525  {
5526  break;
5527  }
5528  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5529  }
5530  }
5531  else
5532  {
5533  OneEntryTimetableMemo->Text = Data;
5534  }
5535  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5536 
5537  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5538  {
5539  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5540  TotalLines--;
5541  if(TotalLines < 1)
5542  {
5543  break;
5544  }
5545  }
5546  OneEntryTimetableMemo->HideSelection = true;
5547  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5548  OneEntryTimetableMemo->SelLength = 0;
5550  Utilities->CallLogPop(1602);
5551 }
5552 // ---------------------------------------------------------------------------
5553 
5555 {
5556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5557  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5558  {
5559  HighlightPanel->Top = 32;
5560  HighlightPanel->Caption = "";
5561  HighlightPanel->Width = 100;
5562  HighlightPanel->Visible = false;
5563  }
5564  else
5565  {
5566  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5567  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5568  {
5569  for(int x = 1; x < CurrentStr.Length(); x++)
5570  {
5571  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5572  {
5573  CurrentStr = CurrentStr.SubString(1, (x - 1));
5574  }
5575  }
5576  }
5577  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5578  if(HighlightPanel->Top < 32)
5579  {
5580  HighlightPanel->Visible = false;
5581  }
5582  else
5583  {
5584  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5585  }
5586  HighlightPanel->Caption = CurrentStr;
5587  if(AllEntriesTTListBox->Items->Count > 47) // because the scrollbar will be present
5588  {
5589  HighlightPanel->Width = 82;
5590  }
5591  else
5592  {
5593  HighlightPanel->Width = 100;
5594  }
5595  }
5596  Utilities->CallLogPop(1709);
5597 }
5598 
5599 // ---------------------------------------------------------------------------
5601 {
5602  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5603  {
5604  return(false);
5605  }
5606  TDateTime DummyTime;
5607  bool TimesPresent = false;
5608 
5609  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5610  {
5611  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5612  {
5613  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5614  {
5615  TimesPresent = true;
5616  break;
5617  }
5618  }
5619  if(TimesPresent)
5620  {
5621  break;
5622  }
5623  }
5624  return(TimesPresent);
5625 }
5626 
5627 // ---------------------------------------------------------------------------
5628 // end of Timetable editing functions
5629 // ---------------------------------------------------------------------------
5630 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5631 {
5632  try
5633  {
5634  TrainController->LogEvent("ExitMenuItemClick");
5635  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5637  {
5638  UnicodeString MessageStr =
5639  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5640  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5641  if(button == IDNO)
5642  {
5643  Utilities->CallLogPop(1711);
5644  return;
5645  }
5646  }
5647  if(FileChangedFlag)
5648  {
5649  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5650  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5651  if(button == IDNO)
5652  {
5653  Utilities->CallLogPop(1180);
5654  return;
5655  }
5656  }
5657  if((TempTTFileName != "") && FileExists(TempTTFileName))
5658  {
5659  DeleteFile(TempTTFileName);
5660  }
5661  Utilities->CallLogPop(1181);
5662  Application->Terminate();
5663  }
5664  catch(const Exception &e)
5665  {
5666  ErrorLog(140, e.Message);
5667  }
5668 }
5669 // ---------------------------------------------------------------------------
5670 
5671 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5672 {
5673  try
5674  {
5675  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5676  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5677  if(TrackInfoOnOffMenuItem->Caption == "Show")
5678  {
5679  TrackInfoOnOffMenuItem->Caption = "Hide";
5680  }
5681  else
5682  {
5683  TrackInfoOnOffMenuItem->Caption = "Show";
5684  }
5685  Utilities->CallLogPop(1183);
5686  }
5687  catch(const Exception &e)
5688  {
5689  ErrorLog(173, e.Message);
5690  }
5691 }
5692 // ---------------------------------------------------------------------------
5693 
5694 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5695 {
5696  try
5697  {
5698  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5699  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5700  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5701  {
5702  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5703  }
5704  else
5705  {
5706  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5707  }
5708  Utilities->CallLogPop(1184);
5709  }
5710  catch(const Exception &e)
5711  {
5712  ErrorLog(141, e.Message);
5713  }
5714 }
5715 
5716 // ---------------------------------------------------------------------------
5717 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5718 {
5719  try
5720  {
5721  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5722  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5723  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5724  {
5725  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5726  }
5727  else
5728  {
5729  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5730  }
5731  Utilities->CallLogPop(1185);
5732  }
5733  catch(const Exception &e)
5734  {
5735  ErrorLog(142, e.Message);
5736  }
5737 }
5738 
5739 // ---------------------------------------------------------------------------
5740 // Dragging Functions
5741 // ---------------------------------------------------------------------------
5742 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5743 {
5744 // allow in zoom out mode
5745  try
5746  {
5747 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5748  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5749  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5750  {
5751  Accept = true;
5752  int PPLeft = PerformancePanel->Left;
5753  int PPTop = PerformancePanel->Left;
5754 
5755  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5756  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5757  if((PPLeft + PerformancePanel->Width) < 32)
5758  {
5759  PPLeft = 32 - PerformancePanel->Width;
5760  }
5761  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5762  {
5763  PPLeft = MainScreen->Left + MainScreen->Width;
5764  }
5765  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5766  {
5767  PPTop = MainScreen->Top - PerformancePanel->Height;
5768  }
5769  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5770  {
5771  PPTop = MainScreen->Top + MainScreen->Height - 20;
5772  }
5773  PerformancePanel->Left = PPLeft;
5774  PerformancePanel->Top = PPTop;
5775  }
5776  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5777  // not the listbox because that used for selecting trains
5778  {
5779  Accept = true;
5780  int OALeft = OperatorActionPanel->Left;
5781  int OATop = OperatorActionPanel->Left;
5782 
5783  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5784  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5785  if((OALeft + OperatorActionPanel->Width) < 32)
5786  {
5787  OALeft = 32 - OperatorActionPanel->Width;
5788  }
5789  if(OALeft > (MainScreen->Left + MainScreen->Width))
5790  {
5791  OALeft = MainScreen->Left + MainScreen->Width;
5792  }
5793  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5794  {
5795  OATop = MainScreen->Top - OperatorActionPanel->Height;
5796  }
5797  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5798  {
5799  OATop = MainScreen->Top + MainScreen->Height - 20;
5800  }
5801  OperatorActionPanel->Left = OALeft;
5802  OperatorActionPanel->Top = OATop;
5803  }
5804  else
5805  {
5806  Accept = false;
5807  }
5808  Utilities->CallLogPop(1186);
5809  }
5810  catch(const Exception &e)
5811  {
5812  ErrorLog(143, e.Message);
5813  }
5814 }
5815 
5816 // ---------------------------------------------------------------------------
5817 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5818 {
5819 // allow in zoom out mode
5820  try
5821  {
5822  TrainController->LogEvent("PerformancePanelStartDrag");
5823  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5824  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5825  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5826  Utilities->CallLogPop(1187);
5827  }
5828  catch(const Exception &e)
5829  {
5830  ErrorLog(144, e.Message);
5831  }
5832 }
5833 // ---------------------------------------------------------------------------
5834 
5835 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5836 
5837 {
5838 // allow in zoom out mode
5839  try
5840  {
5841  TrainController->LogEvent("OperatorActionPanelStartDrag");
5842  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5843  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5844  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5845  Utilities->CallLogPop(2091);
5846  }
5847  catch(const Exception &e)
5848  {
5849  ErrorLog(201, e.Message);
5850  }
5851 }
5852 
5853 // ---------------------------------------------------------------------------
5854 // Mouse Functions
5855 // ---------------------------------------------------------------------------
5856 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5857 // caller function - stops master clock
5858 {
5859 // have to allow in zoom out mode
5860  try
5861  {
5862  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5863  bool ClockState = Utilities->Clock2Stopped;
5864  Utilities->Clock2Stopped = true;
5865 
5866  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5867  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5868  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5869  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5870  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5871 
5873  {
5874  if(!Display->ZoomOutFlag)
5875  {
5876  MainScreenMouseDown2(0, Button, Shift, X, Y);
5877  }
5878  else
5879  {
5880  MainScreenMouseDown3(0, Button, Shift, X, Y);
5881  }
5882  }
5883  Utilities->Clock2Stopped = ClockState;
5884  Utilities->CallLogPop(33);
5885  }
5886  catch(const Exception &e)
5887  {
5888  ErrorLog(19, e.Message);
5889  }
5890 }
5891 
5892 // ---------------------------------------------------------------------------
5893 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5894 {
5895  try
5896  {
5897  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5899  "," + AnsiString(Y));
5900  // unplot GapFlash graphics if plotted & cancel gap flashing if left mouse button pressed (so can move display with right mouse button)
5901  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5902  if(Track->GapFlashFlag && !Display->ZoomOutFlag && (Button == mbLeft))
5903  {
5906  Track->GapFlashFlag = false;
5907  }
5908  int HLoc, VLoc;
5909  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5910  int NoOffsetX, NoOffsetY;
5911  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5912  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5913  {
5914  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5915  int Dummy; // unused in next function
5916  AnsiString Text = ""; // needed for TextFound but not used
5917  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X,
5918  Y, Dummy) && !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5919  {
5922  WholeRailwayMoving = true;
5923  Screen->Cursor = TCursor(-22); // Four arrows;
5924  }
5925 
5926  else if(Level2TrackMode == AddText)
5927  {
5928  TrainController->LogEvent("mbRight + AddText");
5929 // ResetChangedFileDataAndCaption(, true); moved from here after 2.7.0 in case no changes made
5930  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5931  {
5932  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
5933  {
5934  ResetChangedFileDataAndCaption(2, true); // moved to here after 2.7.0
5936  if(NoRailway())
5937  {
5938  EditMenu->Enabled = false;
5939  }
5940  else
5941  {
5942  EditMenu->Enabled = true;
5943  }
5944  }
5945  }
5946  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5947  Utilities->CallLogPop(34);
5948  return;
5949  }
5950  else if(Level2TrackMode == AddGraphic)
5951  {
5952  TrainController->LogEvent("mbRight + AddGraphic");
5953  if(Track->UserGraphicVector.empty()) // no user graphics
5954  {
5955  Utilities->CallLogPop(2180);
5956  return;
5957  }
5958  int UGIVecPos;
5959  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
5960  {
5961  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
5963  if(NoRailway())
5964  {
5965  EditMenu->Enabled = false;
5966  }
5967  else
5968  {
5969  EditMenu->Enabled = true;
5970  }
5971  }
5972  Utilities->CallLogPop(2181);
5973  return;
5974  }
5975 
5976  else if(Level2TrackMode == AddTrack)
5977  {
5978  TrainController->LogEvent("mbRight + AddTrack");
5979  bool TrackEraseSuccessfulFlag;
5980  int ErasedTrackVectorPosition;
5981  Screen->Cursor = TCursor(-11); // Hourglass;
5982  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
5983  if(TrackEraseSuccessfulFlag)
5984  {
5985  if(ErasedTrackVectorPosition > -1)
5986  {
5987  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
5988  }
5991  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
5992  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
5993  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
5994  if(Track->GapsUnset(1))
5995  {
5996  SetGapsButton->Enabled = true;
5997  }
5998  // only enable if there are gaps still to be set (returns false for no track)
5999  else
6000  {
6001  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
6002  {
6003  TrackOKButton->Enabled = true;
6004  }
6005  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6006  }
6007  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6008  {
6009  SetLengthsButton->Enabled = false;
6010  }
6011 // if(NoRailway()) dropped at v2.6.0 to allow edits during AddTrack
6012 // {
6013 // EditMenu->Enabled = false;
6014 // }
6015 // else
6016  EditMenu->Enabled = true;
6017  }
6018  Screen->Cursor = TCursor(-2); // Arrow
6019  Utilities->CallLogPop(35);
6020  return;
6021  }
6022  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
6023  {
6024  TrainController->LogEvent("mbRight + DistanceContinuing");
6025 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 as may only be checking existing distances/speeds. Moved to button clicks in TrackLengthPanel
6026  bool LeadingPointsAtLastElement = false;
6027  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
6028  {
6029  if(ConstructPrefDir->PrefDirSize() == 0)
6030  {
6032  SetLevel1Mode(64);
6034  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
6035  Utilities->CallLogPop(1526);
6036  return;
6037  }
6040  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6041  if(!LeadingPointsAtLastElement)
6042  {
6043  TrackLengthPanel->Visible = true;
6044  TrackLengthPanel->SetFocus();
6045  InfoPanel->Visible = true;
6046  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6047  RestoreAllDefaultLengthsButton->Enabled = true;
6048  ResetDefaultLengthButton->Enabled = true;
6049  LengthOKButton->Enabled = true;
6050  DistanceBox->Text = AnsiString(OverallDistance);
6051  if(OverallSpeedLimit > -1)
6052  {
6053  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6054  }
6055  else
6056  {
6057  SpeedLimitBox->Text = "Mixed";
6058  }
6059  }
6060  else
6061  {
6062  TrackLengthPanel->Visible = true;
6063  TrackLengthPanel->SetFocus();
6064  InfoPanel->Visible = true;
6065  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
6066  RestoreAllDefaultLengthsButton->Enabled = false;
6067  ResetDefaultLengthButton->Enabled = false;
6068  LengthOKButton->Enabled = false;
6069  }
6071  }
6072  Utilities->CallLogPop(36);
6073  return;
6074  }
6075 
6076  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
6077  {
6078  TrainController->LogEvent("mbRight + PrefDirContinuing");
6079 // ResetChangedFileDataAndCaption(, false); moved to later after 2.7.0 as may not change anything
6080 // RlyFile = false; - don't alter this just for PrefDir changes
6081  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
6082  {
6083  if(ConstructPrefDir->PrefDirSize() == 0)
6084  {
6086  SetLevel1Mode(14); // all PrefDir truncated
6087  Utilities->CallLogPop(37);
6088  return;
6089  }
6091  ResetChangedFileDataAndCaption(5, false); // moved to here after 2.7.0
6092  }
6094  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
6095  Utilities->CallLogPop(38);
6096  return;
6097  }
6098 
6099  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
6100  {
6101  TrainController->LogEvent("mbRight + != PrefDirContinuing");
6103 // RlyFile = false; - don't alter this just for PrefDir changes
6106  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
6107  Utilities->CallLogPop(39);
6108  return;
6109  }
6110 
6111  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
6112  {
6113  TrainController->LogEvent("mbRight + OperMode");
6114  bool FoundFlag;
6115  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
6116  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
6117  {
6119  // signaller control of train
6120  if(SelectedTrainID > -1)
6121  {
6124  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
6125  {
6126  if(Train.TrainMode == Signaller)
6127  {
6129  }
6130  }
6131  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
6133  !Train.StepForwardFlag))
6134  // don't allow signaller popup menu in timetable mode unless stopped,
6135  // or when coming to a stop or leaving at a continuation when under signaller control
6136  // or when failed
6137  {
6138  // don't allow selection if another stopped train at a bridge position
6139  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
6140  {
6141  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
6142  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
6143  if((TrainID01 > -1) && (TrainID23 > -1))
6144  {
6145  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
6146  Utilities->CallLogPop(1103);
6147  return;
6148  }
6149  }
6150  if(Train.TrainMode == Timetable)
6151  {
6152  TakeSignallerControlMenuItem->Enabled = true;
6153  TimetableControlMenuItem->Enabled = false;
6154  ChangeDirectionMenuItem->Enabled = false;
6155  MoveForwardsMenuItem->Enabled = false;
6156  SignallerJoinedByMenuItem->Enabled = false;
6157  RepairFailedTrainMenuItem->Enabled = false;
6158  StepForwardMenuItem->Enabled = false;
6159  RemoveTrainMenuItem->Enabled = false;
6160  PassRedSignalMenuItem->Enabled = false;
6161  SignallerControlStopMenuItem->Enabled = false;
6162  }
6163  else // signaller mode
6164  {
6165  TakeSignallerControlMenuItem->Enabled = false;
6166  if((Train.Crashed) || (Train.Derailed))
6167  {
6168  TimetableControlMenuItem->Enabled = false;
6169  ChangeDirectionMenuItem->Enabled = false;
6170  MoveForwardsMenuItem->Enabled = false;
6171  SignallerJoinedByMenuItem->Enabled = false;
6172  RepairFailedTrainMenuItem->Enabled = false;
6173  StepForwardMenuItem->Enabled = false;
6174  PassRedSignalMenuItem->Enabled = false;
6175  SignallerControlStopMenuItem->Enabled = false;
6176  RemoveTrainMenuItem->Enabled = true;
6177  }
6178  else if(Train.Stopped())
6179  {
6180  if(Train.TimetableFinished)
6181  {
6182  TimetableControlMenuItem->Enabled = false;
6183  }
6184  else
6185  {
6186  if(Train.RestoreTimetableLocation == "") // en route
6187  {
6188  TimetableControlMenuItem->Enabled = true;
6189  }
6190  else
6191  {
6192  // obtain train location & check if OK for restoration of tt control
6193  AnsiString LocName = "";
6194  if(Train.LeadElement > -1)
6195  {
6196  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
6197  }
6198  if((LocName == "") && (Train.MidElement > -1))
6199  {
6200  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
6201  }
6202  if(Train.RestoreTimetableLocation == LocName)
6203  {
6204  TimetableControlMenuItem->Enabled = true;
6205  }
6206  else
6207  {
6208  TimetableControlMenuItem->Enabled = false;
6209  }
6210  }
6211  }
6212 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
6213  ChangeDirectionMenuItem->Enabled = true;
6214  if(Train.LeadElement > -1)
6215  {
6217  {
6218  ChangeDirectionMenuItem->Enabled = false;
6219  }
6220  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
6221  {
6222  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
6223  .TrackType == Continuation)
6224  {
6225  ChangeDirectionMenuItem->Enabled = false;
6226  }
6227  }
6228  }
6229  else
6230  {
6231  ChangeDirectionMenuItem->Enabled = false;
6232  }
6233  if(Train.MidElement > -1)
6234  {
6236  {
6237  ChangeDirectionMenuItem->Enabled = false;
6238  }
6239  }
6240  else
6241  {
6242  ChangeDirectionMenuItem->Enabled = false;
6243  }
6244  if(Train.LagElement > -1)
6245  {
6247  {
6248  ChangeDirectionMenuItem->Enabled = false;
6249  }
6250  }
6251  RemoveTrainMenuItem->Enabled = true;
6252  SignallerControlStopMenuItem->Enabled = false;
6253  SignallerJoinedByMenuItem->Enabled = false;
6254  RepairFailedTrainMenuItem->Enabled = false;
6255  StepForwardMenuItem->Enabled = false;
6256  MoveForwardsMenuItem->Enabled = false;
6257  PassRedSignalMenuItem->Enabled = false;
6258  if(Train.AbleToMove(0))
6259  {
6260  MoveForwardsMenuItem->Enabled = true;
6262  {
6263  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
6264  }
6265  } // fails on trying to calc AutoSig time delay for resetting signals
6266 
6267  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
6268  {
6269  PassRedSignalMenuItem->Enabled = true;
6270  StepForwardMenuItem->Enabled = true;
6271  }
6272  TTrain *AdjacentTrain;
6273  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
6274  {
6275  SignallerJoinedByMenuItem->Enabled = true;
6276  }
6277  if(Train.TrainFailed)
6278  {
6279  RepairFailedTrainMenuItem->Enabled = true;
6280  }
6281  }
6282  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
6283  // mid move, & SetTrainMovementValues only intended to be called when stopped
6284  {
6285  TimetableControlMenuItem->Enabled = false;
6286  ChangeDirectionMenuItem->Enabled = false;
6287  RemoveTrainMenuItem->Enabled = false;
6288  MoveForwardsMenuItem->Enabled = false;
6289  SignallerJoinedByMenuItem->Enabled = false;
6290  RepairFailedTrainMenuItem->Enabled = false;
6291  PassRedSignalMenuItem->Enabled = false;
6292  StepForwardMenuItem->Enabled = false;
6293  SignallerControlStopMenuItem->Enabled = true;
6294  }
6295  }
6296  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
6297  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6299  PopupMenu->Popup(MainScreen->Left + X, MainScreen->Top + Y + 43); // menu stops everything so reset timetable time when restarts,
6300  // new at v2.6.1, displays so that can't inadvertently click on a selection if click twice
6301  // 43 is the distance from the top of the screen to the top of TInterface
6302  TrainController->BaseTime = TDateTime::CurrentDateTime();
6304  Utilities->CallLogPop(40);
6305  return;
6306  }
6307  }
6308  }
6309  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
6310  {
6311  TrainController->LogEvent("mbRight + RouteContinuing");
6313  Utilities->CallLogPop(41);
6314  return;
6315  }
6316 
6317  else if(RouteCancelFlag) // allow in PreStart
6318  {
6319  TrainController->LogEvent("mbRight + RouteCancelFlag");
6320  Screen->Cursor = TCursor(-11); // Hourglass;
6321  // stop clock as sometimes takes several seconds
6322  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6324  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
6325  {
6326  ClearandRebuildRailway(6); // to replot new shorter route
6327  }
6329  TrainController->BaseTime = TDateTime::CurrentDateTime();
6331  Screen->Cursor = TCursor(-2); // Arrow
6332  }
6333 
6334  else // gap flashing, don't allow to interfere with RouteCancelFlag
6335  {
6336  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
6337  int Position;
6338  TTrackElement TrackElement;
6339  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement))
6340  {
6341  ;
6342  }
6343  {
6344  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6345  {
6346  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
6347  {
6348  // don't flash if train on either gap element
6349  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6354  Track->GapFlashRedPosition = Position;
6359  Track->GapFlashFlag = true;
6360  }
6361  }
6362  }
6363  Utilities->CallLogPop(42);
6364  return; // covers above else & included here in case any more usermodes added later
6365  }
6366  }
6367  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
6368  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
6369  int Position;
6370  TTrackElement TrackElement;
6371  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement))
6372  {
6373  ;
6374  }
6375  {
6376  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6377  {
6378  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
6379  {
6380  // don't flash if train on either gap element
6381  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6385  Track->GapFlashRedPosition = Position;
6389  Track->GapFlashFlag = true;
6390  }
6391  }
6392  }
6393  Utilities->CallLogPop(67);
6394  return; // covers above else & included here in case any more usermodes added later
6395  }
6396 // Left Mouse Button Functions
6397  if(RouteCancelFlag)
6398  {
6400  }
6401  mbLeftDown = true;
6402 
6403  if(Level2TrackMode == AddTrack)
6404  {
6405  TrainController->LogEvent("mbLeft + AddTrack");
6406  Screen->Cursor = TCursor(-11); // Hourglass;
6408  bool TrackLinkingRequiredFlag;
6409  int CurrentTag;
6410  TSpeedButton *TempSpeedButton = 0;
6411  if(CurrentSpeedButton)
6412  {
6413  CurrentTag = CurrentSpeedButton->Tag;
6414  TempSpeedButton = CurrentSpeedButton;
6415  }
6416  else
6417  {
6418  CurrentTag = 0;
6419  }
6420  bool InternalChecks = true;
6421  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6422  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6423  EditMenu->Enabled = true;
6424  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6425  {
6426  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6427  }
6428  if(TrackLinkingRequiredFlag)
6429  {
6430  Track->SetTrackFinished(false);
6431  }
6432  SetTrackBuildImages(10);
6433  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6434  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6435  if(Track->GapsUnset(2))
6436  {
6437  SetGapsButton->Enabled = true;
6438  }
6439  // only enable if there are gaps still to be set (returns false for no track)
6440  else
6441  {
6442  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6443  {
6444  TrackOKButton->Enabled = true;
6445  }
6446  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6447  }
6448  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6449  {
6450  SetLengthsButton->Enabled = false;
6451  }
6452  if(TempSpeedButton) // restore button if was pressed
6453  {
6454  CurrentSpeedButton = TempSpeedButton;
6455  CurrentSpeedButton->Down = true;
6456  }
6457  Screen->Cursor = TCursor(-2); // Arrow
6458  Utilities->CallLogPop(44);
6459  return;
6460  }
6461 
6462  else if(Level2TrackMode == AddGraphic)
6463  {
6464  TrainController->LogEvent("mbLeft + AddGraphic");
6465 // ResetChangedFileDataAndCaption(, false); //moved to later after 2.7.0 in case can't find it
6466  TUserGraphicItem NewGI;
6467  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6468  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6469  {
6470  NewGI.UserGraphic = UGMIt->second;
6471  NewGI.Width = UGMIt->second->Width;
6472  NewGI.Height = UGMIt->second->Height;
6474  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6475  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6476  Track->UserGraphicVector.push_back(NewGI);
6477  Display->PlotAndAddUserGraphic(1, NewGI);
6478  ResetChangedFileDataAndCaption(24, false); // moved to here after 2.7.0
6479  }
6480  else
6481  {
6482  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6483  Utilities->CallLogPop(2195);
6484  return;
6485  }
6486  MoveTextOrGraphicButton->Enabled = true;
6487  EditMenu->Enabled = true;
6488  Utilities->CallLogPop(2182);
6489  return;
6490  }
6491 
6492  else if(Level2TrackMode == AddLocationName)
6493  {
6494  TrainController->LogEvent("mbLeft + AddLocationName");
6495 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to LocationNameKeyUp in case nothing changed
6496  bool FoundFlag;
6497  TTrackElement TrackElement;
6498  AnsiString NameString;
6499  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6500  if(!FoundFlag)
6501  {
6502  Utilities->CallLogPop(45);
6503  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6504  }
6505  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6506  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6507  TTrackElement& ValidElement = InactiveTrackElement1;
6508  unsigned int ValidPosition;
6509  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6510  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6511  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6512  {
6513  Utilities->CallLogPop(46);
6514  return; // element not valid
6515  }
6516  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6517  (InactiveTrackElement1.TrackType == Concourse))
6518  {
6519  ValidElement = InactiveTrackElement1;
6520  ValidPosition = InactivePair.first;
6521  }
6522  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6523  (InactiveTrackElement2.TrackType == Concourse))
6524  {
6525  ValidElement = InactiveTrackElement2;
6526  ValidPosition = InactivePair.second;
6527  }
6528  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6529 
6530  // put a square box round element to show selection
6531  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6532  LocationNameTextBox->Visible = true;
6533  LocationNameTextBox->SetFocus();
6534  NameString = Track->GetLocationName(ValidPosition);
6535  LocationNameTextBox->Text = NameString;
6536  InfoPanel->Visible = true;
6537  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6538 
6539  Track->LNPendingList.clear();
6540  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6541  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6542  Utilities->CallLogPop(47);
6543  return;
6544  }
6545 
6546  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6547  // prior to selecting start element
6548  {
6549  TrainController->LogEvent("mbLeft + DistanceStart");
6550 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6551  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6552  {
6555  SetLevel1Mode(65);
6557  SetLevel2TrackMode(30);
6558  }
6559  Utilities->CallLogPop(48);
6560  return;
6561  }
6562 
6563  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6564  // prior to selecting finish element
6565  {
6566  TrainController->LogEvent("mbLeft + DistanceContinuing");
6567 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6568  bool FinishElement = false, LeadingPointsAtLastElement = false;
6569  Screen->Cursor = TCursor(-11); // Hourglass;
6570  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6571  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6572  {
6573  // not same as start element
6574  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6575  {
6578  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6579  if(FinishElement)
6580  {
6581  TrackLengthPanel->Visible = true;
6582  TrackLengthPanel->SetFocus();
6583  InfoPanel->Visible = true;
6584  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6585  RestoreAllDefaultLengthsButton->Enabled = true;
6586  ResetDefaultLengthButton->Enabled = true;
6587  LengthOKButton->Enabled = true;
6588  DistanceBox->Text = AnsiString(OverallDistance);
6589  if(OverallSpeedLimit > -1)
6590  {
6591  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6592  }
6593  else
6594  {
6595  SpeedLimitBox->Text = "Mixed";
6596  }
6598  Screen->Cursor = TCursor(-2); // Arrow
6599  Utilities->CallLogPop(1527);
6600  return;
6601  }
6602  else
6603  {
6604  if(!LeadingPointsAtLastElement)
6605  {
6606  TrackLengthPanel->Visible = true;
6607  TrackLengthPanel->SetFocus();
6608  InfoPanel->Visible = true;
6609  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6610  RestoreAllDefaultLengthsButton->Enabled = true;
6611  ResetDefaultLengthButton->Enabled = true;
6612  LengthOKButton->Enabled = true;
6613  DistanceBox->Text = AnsiString(OverallDistance);
6614  if(OverallSpeedLimit > -1)
6615  {
6616  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6617  }
6618  else
6619  {
6620  SpeedLimitBox->Text = "Mixed";
6621  }
6622  // Level2TrackMode = DistanceContinuing;
6623  // SetLevel2TrackMode();
6624  }
6625  else
6626  {
6627  TrackLengthPanel->Visible = true;
6628  TrackLengthPanel->SetFocus();
6629  InfoPanel->Visible = true;
6630  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6631  RestoreAllDefaultLengthsButton->Enabled = false;
6632  ResetDefaultLengthButton->Enabled = false;
6633  LengthOKButton->Enabled = false;
6634  // Level2TrackMode = DistanceContinuing;
6635  // SetLevel2TrackMode();
6636  }
6637  }
6638  }
6639  }
6640  else // same as start element
6641  {
6644  SetLevel2TrackMode(54);
6645  Screen->Cursor = TCursor(-2); // Arrow
6646  Utilities->CallLogPop(1713);
6647  return;
6648  }
6650  Screen->Cursor = TCursor(-2); // Arrow
6651  Utilities->CallLogPop(1490);
6652  return;
6653  }
6654 
6655  else if(Level2TrackMode == GapSetting)
6656  {
6657  TrainController->LogEvent("mbLeft + GapSetting");
6658 // ResetChangedFileDataAndCaption(, true); moved to later after 2.7.0 in case can't set it
6659  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6660  // & it is highlighted
6661  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6662  {
6663  Utilities->CallLogPop(50);
6664  return; // true if finds one
6665  }
6666  ResetChangedFileDataAndCaption(11, true); // moved to here after 2.7.0 in case can't set it
6667  InfoPanel->Visible = true;
6668  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6669  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6670  Delay(0, 500); // 500 msec delay before next selection requested
6671 
6672  // ClearandRebuildRailway(8);//get rid of gap selections
6673  // need to call this later when new gap displayed, else old gap remains
6674 
6675  // now back to highlighting next gap
6676  // bool LocError = false;
6677  if(!(HighLightOneGap(1, HLoc, VLoc)))
6678  {
6679  // all gaps set
6680  ShowMessage("All gaps set");
6681  if(Level2TrackMode == AddTrack)
6682  {
6684  SetLevel1Mode(66);
6685  SetLevel2TrackMode(31);
6686  }
6687  else
6688  {
6690  SetLevel1Mode(37);
6691  }
6692  ClearandRebuildRailway(9); // get rid of last gap ellipse
6693  Utilities->CallLogPop(51);
6694  return;
6695  }
6696  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6697  // by another call to MainScreenMouseDown
6698  }
6699 
6700  else if(Level2TrackMode == AddText)
6701  {
6702  TrainController->LogEvent("mbLeft + AddText");
6703 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to TextBoxKeyPress in case nothing changed
6704  // X & Y are relative to Display output, but TextBox is placed relative to Form
6705  // if mouse position on first character of an existing piece of text reload it into the editor
6706 
6707  bool TextFoundFlag = false;
6708  int TrueX = 0, TrueY = 0;
6709  AnsiString ExistingText = "";
6711  TFont *ExistingTextFont = new TFont;
6712  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6713  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6714  if(!TextHandler->TextVector.empty())
6715  {
6716  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6717  {
6718  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6719  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6720  {
6721  ExistingText = TextPtr->TextString;
6722  ExistingTextFont->Assign(TextPtr->Font);
6723  ExistingTextHPos = TextPtr->HPos;
6724  ExistingTextVPos = TextPtr->VPos;
6725  TextFoundFlag = true;
6726  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6727  break;
6728  } // if ....
6729 
6730  } // for TextPtr...
6731  } // if !TextVector...
6732 
6733  if(TextFoundFlag)
6734  {
6735  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6736  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6737  TextBox->Font->Assign(ExistingTextFont);
6738  Display->SetFont(ExistingTextFont);
6739  Text_X = ExistingTextHPos;
6740  Text_Y = ExistingTextVPos;
6741  }
6742  else
6743  {
6744  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6745  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6746  TextBox->Font->Assign(Display->GetFont());
6747  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6748  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6749  }
6750  TextBox->Visible = true;
6751  TextBox->SetFocus();
6752  if(TextFoundFlag)
6753  {
6754  TextBox->Text = ExistingText;
6755  }
6756  else
6757  {
6758  TextBox->Text = "New Text: CR=end, ESC=quit";
6759  }
6760  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6761  TextBox->SelectAll();
6762  delete ExistingTextFont;
6763  ClearandRebuildRailway(29); // to remove old text if replaced
6765  Utilities->CallLogPop(1775);
6766  return; // If text input go no further
6767  }
6768 
6770  {
6771  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6772 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case nothing found
6773  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6774  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6775  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6776  // StartX = X + (Display->DisplayOffsetH * 16);
6777  // StartY = Y + (Display->DisplayOffsetV * 16);
6780  if(!TextFoundFlag) // give precedence to text
6781  {
6784  {
6785  ResetChangedFileDataAndCaption(13, true); // moved here after 2.7.0 to save only if something found
6786  }
6787  }
6788  else
6789  {
6790  ResetChangedFileDataAndCaption(27, true); // and here
6791  }
6792  Utilities->CallLogPop(53);
6793  return; // if text move selected don't permit anything else
6794  }
6795 
6796  else if(Level2TrackMode == TrackSelecting)
6797  /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6798  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6799  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6800  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6801  selected rectangle.
6802  */
6803  {
6804  TrainController->LogEvent("mbLeft + TrackSelecting");
6805  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6806  SelectStartPair.first = HLoc;
6807  SelectStartPair.second = VLoc;
6808  }
6809 
6810  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6811  /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6812  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6813  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6814  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6815  */
6816  {
6817  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6818 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case don't proceed
6819  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6820  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6821  {
6822  SelectPickedUp = false;
6823  Utilities->CallLogPop(54);
6824  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6825  }
6826  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6827  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6828  {
6829  SelectPickedUp = false;
6830  Utilities->CallLogPop(55);
6831  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6832  }
6833  else
6834  {
6835  SelectPickedUp = true;
6836  }
6837  ResetChangedFileDataAndCaption(14, true); // moved here after 2.7.0 in case don't proceed
6840  }
6841 
6843  {
6844  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6845 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6846 // RlyFile = false; - don't alter this just for PrefDir changes
6847  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6848  {
6849  ResetChangedFileDataAndCaption(15, false); // moved after 2.7.0 to here
6853  }
6854  Utilities->CallLogPop(56);
6855  return;
6856  }
6857 
6859  {
6860  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6861 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6862 // RlyFile = false; - don't alter this just for PrefDir changes
6863  bool FinishElement;
6864  Screen->Cursor = TCursor(-11); // Hourglass;
6865  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6866  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6867  {
6868  // not same as start element
6869  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6870  {
6872  ResetChangedFileDataAndCaption(16, false); // moved after 2.7.0 to here
6873  if(FinishElement)
6874  {
6875  ShowMessage("Preferred direction added");
6878  SetLevel1Mode(16);
6879  Screen->Cursor = TCursor(-2); // Arrow
6880  Utilities->CallLogPop(57);
6881  return;
6882  }
6883  else
6884  {
6887  }
6888  // set again since 1st time
6889  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6890  // to do the checks for Loop & End for each element as it is added
6891  }
6892  }
6893  else // same as start element
6894  {
6897  SetLevel1Mode(121);
6898  Screen->Cursor = TCursor(-2); // Arrow
6899  Utilities->CallLogPop(1714);
6900  return;
6901  }
6902  Screen->Cursor = TCursor(-2); // Arrow
6903  Utilities->CallLogPop(58);
6904  return;
6905  }
6906 
6908  {
6909  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6910  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6911  SelectStartPair.first = HLoc;
6912  SelectStartPair.second = VLoc;
6913  }
6914 
6915  else if(Level1Mode == OperMode)
6916  {
6917  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6918  {
6919  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6920  int Position;
6921  TTrackElement TrackElement;
6922  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6923  {
6924  if(TrackElement.TrackType != SignalPost)
6925  {
6926  CallingOnButton->Down = false;
6927 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6929  Utilities->CallLogPop(59);
6930  return;
6931  }
6932  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
6933  {
6935  {
6937  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
6939  {
6940  // found it!
6941 /*
6942  if(TrackElement.SpeedTag == 68)
6943  {
6944  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
6945  }
6946  if(TrackElement.SpeedTag == 69)
6947  {
6948  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
6949  }
6950  if(TrackElement.SpeedTag == 70)
6951  {
6952  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
6953  }
6954  if(TrackElement.SpeedTag == 71)
6955  {
6956  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
6957  }
6958  if(TrackElement.SpeedTag == 72)
6959  {
6960  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
6961  }
6962  if(TrackElement.SpeedTag == 73)
6963  {
6964  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
6965  }
6966  if(TrackElement.SpeedTag == 74)
6967  {
6968  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
6969  }
6970  if(TrackElement.SpeedTag == 75)
6971  {
6972  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
6973  }
6974 */
6975  Track->TrackElementAt(430, Position).CallingOnSet = true;
6976  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
6977 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
6978  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
6979  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
6982  CallingOnButton->Down = false;
6984 
6985 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
6986 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
6987 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
6988  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
6989  {
6990  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
6991  {
6992  // only allow route element to be removed if not selected for a route start otherwise
6993  // StartSelectionRouteID will be set & will fail at convert
6995  {
6997  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
6998  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
6999  AnsiString(PDE.VLoc));
7000  }
7001  }
7002  }
7003 
7004 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
7005  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
7006  {
7007  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
7008  {
7009  // found it
7010  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
7011  // if RouteOrPartRouteSet false then set an unrestricted route into platform
7012  {
7013  bool PointsChanged = false;
7014  IDInt ReqPosRouteID(-1);
7015  TOneRoute *NewRoute = new TOneRoute;
7016  bool CallonTrue = true;
7017  if(NewRoute->GetNonPreferredRouteStartElement(1,
7018  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
7019  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, CallonTrue))
7020  {
7021  if(NewRoute->GetNextNonPreferredRouteElement(1,
7022  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
7023  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, CallonTrue,
7024  ReqPosRouteID, PointsChanged))
7025  {
7026  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
7027  {
7028  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
7029  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
7030  }
7031  }
7032  }
7033  delete NewRoute;
7034  }
7035  }
7036  }
7037 // InfoPanel->Visible = false;
7038  Utilities->CallLogPop(60);
7039  return;
7040  }
7041  }
7042  }
7043  }
7044  CallingOnButton->Down = false;
7046  Utilities->CallLogPop(61);
7047  return;
7048  }
7049 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
7050  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
7051  If any of above conditions not met then treat as route selection, setting route flasher if
7052  route continuing.
7053 */
7054 
7055  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
7056  // disallow route setting if paused
7057  {
7058  if(Level2OperMode == PreStart)
7059  {
7060  PointsFlashDuration = 0.0;
7063  }
7064  else
7065  {
7066  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7067  if(TTClockSpeed < 1)
7068  {
7069  TempSpeedVal = TTClockSpeed;
7070  }
7071  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7074  }
7075  if(RouteMode == RouteNotStarted)
7076  {
7077  TrainController->LogEvent("mbLeft + RouteNotStarted");
7078  int Position;
7079  TTrackElement TrackElement;
7080  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
7081  {
7082  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
7084  // Flash selected points & changeover if appropriate
7085  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
7086  // to ensure user only does one thing at a time
7087  {
7088  if(TrackElement.TrainIDOnElement > -1)
7089  {
7090  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
7091  Utilities->CallLogPop(62);
7092  return;
7093  }
7094  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7095 
7096 /*
7097  This used to try to allow any linked trailing edges to cause both points to change, but no good if
7098  there are two adjacent crossovers, where both trailing edges are linked to two different points.
7099  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
7100  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
7101  ensures that there are no obscure links. Hence better to stick with original.
7102 
7103  //check if trailing edge linked to another point trailing edge
7104  int DivergingPosition = TrackElement.Conn[1];
7105  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
7106  DivergingPointVectorPosition = -1;
7107  if((DivergingElement.TrackType == Points) &&
7108  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7109  {
7110  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7111  {
7112  ShowMessage("Linked points Locked");
7113  }
7114  else DivergingPointVectorPosition = DivergingPosition;
7115  }
7116  else
7117  {
7118  DivergingPosition = TrackElement.Conn[3];
7119  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
7120  if((DivergingElement.TrackType == Points) &&
7121  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7122  {
7123  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7124  {
7125  ShowMessage("Linked points locked");
7126  }
7127  else DivergingPointVectorPosition = DivergingPosition;
7128  }
7129  }
7130  Track->PointFlashFlag = true;
7131  PointFlashVectorPosition = Position;
7132  PointFlashStartTime = TrainController->TTClockTime;
7133  [close curly bracket - if include it matches earlier non-commented one!]
7134 */
7135  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
7136  int DivergingPosition = TrackElement.Conn[3];
7137  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
7138  DivergingPosition))) // full match inc same attributes
7139  {
7140  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
7141  {
7142  TrainController->StopTTClockMessage(2, "Linked points locked");
7143  }
7144  else
7145  {
7146  Track->PointFlashFlag = true;
7147  PointFlashVectorPosition = Position;
7148  DivergingPointVectorPosition = DivergingPosition;
7150  }
7151  }
7152  else // no matching point, just change this point
7153  {
7154  Track->PointFlashFlag = true;
7155  PointFlashVectorPosition = Position;
7158  }
7159  }
7160 
7161  else if(Track->IsLCAtHV(59, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag)
7162  // level crossing added at v2.6.0 to allow manual LC changing
7163  {
7164  if(Track->GetInactiveTrackElementFromTrackMap(5, HLoc, VLoc).Attribute != 2) // 2 = LC changing state, can't click if changing
7165  {
7166  Track->LCChangeFlag = true;
7167  bool TrainPresent = false;
7168  if(Track->IsLCBarrierDownAtHV(4, HLoc, VLoc)) // if true then may be able to raise barriers
7169  {
7170  // first need to identify the LC in the BarriersDownVector
7171  int BDVectorPos = -1;
7172  if(Track->AnyLinkedBarrierDownVectorManual(1, HLoc, VLoc, BDVectorPos)) // looking for same position & manually closed
7173  {
7174  // this largely copied from ClockTimer2
7176  Track->BarriersDownVector.at(BDVectorPos).VLoc, ConstructRoute->SearchVector, TrainPresent))
7177  // returns true for route set or being set or train, and TrainPresent true if train on LC
7178  {
7179  TTrack::TActiveLevelCrossing CLC = Track->BarriersDownVector.at(BDVectorPos);
7180  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7181  TDateTime TempExcessLCDownTime;
7182  if(Track->BarriersDownVector.at(BDVectorPos).ReducedTimePenalty)
7183  // this set in ClockTimer2, relies on train being on LC for >= 1 second
7184  {
7185  // get the 3 mins allowance - hard to imagine will pass in less than a second!
7186  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7187  }
7188  else
7189  {
7190  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7191  }
7192  if(TempExcessLCDownTime > TDateTime(0))
7193  {
7194  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7195  }
7196  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7199  Track->SetLinkedLevelCrossingBarrierAttributes(7, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7200  Track->ChangingLCVector.push_back(CLC);
7201  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + BDVectorPos);
7202  }
7203  }
7204  }
7205  else // lowering
7206  {
7207  // this largely copied from SetLCChangeValues
7208  TTrack::TActiveLevelCrossing ALC; // constructor sets ReducedTimePenalty to false
7209  ALC.HLoc = HLoc;
7210  ALC.VLoc = VLoc;
7212  ALC.BaseElementSpeedTag = TrackElement.SpeedTag;
7215  ALC.TypeOfRoute = 2;
7216  Track->SetLinkedManualLCs(0, HLoc, VLoc);
7217 // this sets all linked LC ConsecSignals values to 2 for manually lowered - differs from SetLCChangeValues which uses the route type
7218  Track->SetLinkedLevelCrossingBarrierAttributes(6, HLoc, VLoc, 2); // set attr to 2 for changing state
7219  Track->ChangingLCVector.push_back(ALC);
7221  {
7222  AnsiString Message =
7223  AnsiString("This will open the level crossing manually (it will show in green).\n\nA manually opened"
7224  " level crossing must be manually closed, and as soon as possible to avoid time penalties.\n\n" "This message will not be shown again."
7225  );
7226  TrainController->StopTTClockMessage(93, Message);
7228  }
7229  }
7230  }
7231  }
7232  else // route start
7233  {
7234  if(AutoSigsFlag)
7235  {
7236  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7238  }
7239  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
7240  {
7241  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7243  }
7244  else
7245  {
7246  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7248  }
7249  if(PreferredRoute)
7250  {
7251  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7252  // another route building
7253  {
7254  ConstructRoute->ClearRoute(); // in case not empty though should be
7256  {
7257  if(AutoSigsFlag)
7258  {
7260  }
7261  else
7262  {
7264  }
7266  InfoPanel->Visible = true;
7267  if(Level2OperMode == PreStart)
7268  {
7269  InfoPanel->Caption = "PRE-START: Select next route location";
7270  }
7271  else
7272  {
7273  InfoPanel->Caption = "OPERATING: Select next route location";
7274  }
7275  }
7276  }
7277  Utilities->CallLogPop(63);
7278  return;
7279  }
7280  else // nonpreferred route
7281  {
7282  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7283  // another route building
7284  {
7285  ConstructRoute->ClearRoute(); // in case not empty though should be
7286  bool CallonFalse = false;
7287  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, CallonFalse))
7288  {
7291  InfoPanel->Visible = true;
7292  if(Level2OperMode == PreStart)
7293  {
7294  InfoPanel->Caption = "PRE-START: Select next route location";
7295  }
7296  else
7297  {
7298  InfoPanel->Caption = "OPERATING: Select next route location";
7299  }
7300  }
7301  }
7302  Utilities->CallLogPop(64);
7303  return;
7304  } // NonPreferred route
7305 
7306  } // TrackType != Points
7307 
7308  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
7309 
7310  } // if(RouteMode == RouteNotStarted)
7311  else // RouteContinuing
7312  {
7313  TrainController->LogEvent("mbLeft + RouteContinuing");
7314  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7317  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
7318  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
7319  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
7320  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
7321  // element, but this sets it to an hourglass while searching
7322  bool PointsChanged = false;
7323  if(PreferredRoute)
7324  {
7325  // route added to AllRoutes in GetNextRouteElement if valid
7326  // int ReqPosRouteNumber;
7328  ConstructRoute->ReqPosRouteID, PointsChanged))
7329  {
7330  Track->RouteFlashFlag = true;
7331  PreferredRouteFlag = true;
7332  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7333  if(TTClockSpeed < 1)
7334  {
7335  TempSpeedVal = TTClockSpeed;
7336  }
7337  if(Level2OperMode == PreStart)
7338  {
7339  RouteFlashDuration = 0.0;
7340  }
7341  else if(PointsChanged)
7342  {
7343  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7344  }
7345  else
7346  {
7347  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7348  }
7349  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for PrefDirRoute
7351  }
7352  else
7353  {
7355  }
7356  Screen->Cursor = TCursor(-2); // Arrow
7357  TrainController->BaseTime = TDateTime::CurrentDateTime();
7359  Utilities->CallLogPop(65);
7360  return;
7361  }
7362  else
7363  {
7364  bool CallonFalse = false;
7365  if(ConstructRoute->GetNextNonPreferredRouteElement(0, HLoc, VLoc, CallonFalse, ConstructRoute->ReqPosRouteID, PointsChanged))
7366  {
7367  Track->RouteFlashFlag = true;
7368  PreferredRouteFlag = false;
7369  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7370  if(TTClockSpeed < 1)
7371  {
7372  TempSpeedVal = TTClockSpeed;
7373  }
7374  if(Level2OperMode == PreStart)
7375  {
7376  RouteFlashDuration = 0.0;
7377  }
7378  else if(PointsChanged)
7379  {
7380  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7381  }
7382  else
7383  {
7384  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7385  }
7386  ConstructRoute->SetRouteFlashValues(2, false, false);
7388  }
7389  else
7390  {
7392  }
7393  }
7394  TrainController->BaseTime = TDateTime::CurrentDateTime();
7396  Screen->Cursor = TCursor(-2); // Arrow
7397  }
7398  Utilities->CallLogPop(66);
7399  return;
7400  }
7401  }
7402  Utilities->CallLogPop(68);
7403  }
7404  catch(const Exception &e)
7405  {
7406  ErrorLog(20, e.Message);
7407  }
7408 }
7409 
7410 // ---------------------------------------------------------------------------
7411 
7412 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
7413 // ZoomOut mode
7414 {
7415 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
7416  try
7417  {
7418  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
7420  "," + AnsiString(Y));
7421  if(Button != mbLeft)
7422  {
7423  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
7426  WholeRailwayMoving = true;
7427  Screen->Cursor = TCursor(-22); // Four arrows;
7428  }
7429  else
7430  {
7431  InfoPanel->Visible = false; // reset infopanel in case not set later
7432  InfoPanel->Caption = "";
7433  int HRounding, VRounding;
7434  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
7435  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
7436  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
7437  if(TruePosH < 0)
7438  {
7439  HRounding = -(Utilities->ScreenElementWidth / 4);
7440  }
7441  else
7442  {
7443  HRounding = (Utilities->ScreenElementWidth / 4);
7444  }
7445  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
7446  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
7447  {
7448  CentreH -= (Utilities->ScreenElementWidth / 2);
7449  }
7450  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
7451  {
7452  CentreH += (Utilities->ScreenElementWidth / 2);
7453  }
7454  if(TruePosV < 0)
7455  {
7456  VRounding = -(Utilities->ScreenElementHeight / 4);
7457  }
7458  else
7459  {
7460  VRounding = (Utilities->ScreenElementHeight / 4);
7461  }
7462  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
7463  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
7464  {
7465  CentreV -= (Utilities->ScreenElementHeight / 2);
7466  }
7467  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
7468  {
7469  CentreV += (Utilities->ScreenElementHeight / 2);
7470  }
7471  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
7473 
7474  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
7475  if(Level1Mode == BaseMode)
7476  {
7477  SetLevel1Mode(17);
7478  }
7479  else if(Level1Mode == TrackMode)
7480  {
7481  // set edit menu items
7483  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
7484  // displayed gap, user wants to display the clicked area
7485  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
7486  PreventGapOffsetResetting = false;
7487  }
7488  else if(Level1Mode == PrefDirMode)
7489  {
7491  {
7492  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
7493  }
7494  else
7495  {
7496  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
7497  }
7498  }
7499  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
7500  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
7501  else if(Level1Mode == TimetableMode)
7502  {
7503  InfoPanel->Visible = false;
7504  }
7505  // Not OperMode or RestartSessionOperMode as that resets the performance file
7506  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
7507  {
7508  OperateButton->Enabled = true;
7509  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
7510  ExitOperationButton->Enabled = true;
7512  }
7513  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
7514  {
7515  OperateButton->Enabled = true;
7516  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7517  ExitOperationButton->Enabled = true;
7518  TTClockAdjButton->Enabled = true;
7521  }
7522  else if(TempLevel2OperMode == PreStart)
7523  {
7524  OperateButton->Enabled = true;
7525  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7526  ExitOperationButton->Enabled = true;
7527  TTClockAdjButton->Enabled = true;
7529  }
7530  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7533  }
7534  Utilities->CallLogPop(69);
7535  }
7536  catch(const Exception &e)
7537  {
7538  ErrorLog(21, e.Message);
7539  }
7540 }
7541 
7542 // ---------------------------------------------------------------------------
7543 
7544 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7545 {
7546  try
7547  {
7548  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7549  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7550 
7551  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7552  {
7553  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7555  if(X < 0)
7556  {
7557  X = 0; // ensure pointer stays within display area
7558  }
7559  if(X > (MainScreen->Width - 1))
7560  {
7561  X = MainScreen->Width - 1;
7562  }
7563  if(Y < 0)
7564  {
7565  Y = 0;
7566  }
7567  if(Y > (MainScreen->Height - 1))
7568  {
7569  Y = MainScreen->Height - 1;
7570  }
7571  if(!Display->ZoomOutFlag)
7572  {
7573  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7574  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7575  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7576  {
7577  int NewH = X - StartWholeRailwayMoveHPos;
7578  int NewV = Y - StartWholeRailwayMoveVPos;
7579  Display->DisplayOffsetH -= NewH / 16;
7580  Display->DisplayOffsetV -= NewV / 16;
7581  StartWholeRailwayMoveHPos = X - StartOffsetX;
7582  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7585  {
7587  }
7588  }
7589  }
7590 
7591  else
7592  {
7593  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7594  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7595  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7596  {
7597  int NewH = X - StartWholeRailwayMoveHPos;
7598  int NewV = Y - StartWholeRailwayMoveVPos;
7599  Display->DisplayZoomOutOffsetH -= NewH / 4;
7600  Display->DisplayZoomOutOffsetV -= NewV / 4;
7601  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7602  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7603  Display->ClearDisplay(10);
7605  }
7606  }
7607  TrainController->BaseTime = TDateTime::CurrentDateTime();
7609  }
7610 
7611  else if(mbLeftDown)
7612  {
7614  /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7615  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7616  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7617  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7618  selected rectangle.
7619  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7620  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7621  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7622  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7623  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7624  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7625  the selection.
7626  */
7627  {
7628  TrainController->LogEvent("MouseMove + TrackSelecting");
7629  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7630  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7631  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7632  // rightmost point and the VLoc value of the bottommost point
7633  if(CurrentHLoc >= StartHLoc)
7634  {
7635  CurrentHLoc++;
7636  }
7637  else
7638  {
7639  StartHLoc++;
7640  }
7641  if(CurrentVLoc >= StartVLoc)
7642  {
7643  CurrentVLoc++;
7644  }
7645  else
7646  {
7647  StartVLoc++;
7648  }
7649  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7650  {
7652  }
7653  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7654  {
7656  }
7657  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7658  {
7659  CurrentHLoc = Display->DisplayOffsetH;
7660  }
7661  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7662  {
7663  CurrentVLoc = Display->DisplayOffsetV;
7664  }
7665  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7666  ClearandRebuildRailway(14); // to clear earlier rectangles
7667  Display->PlotDashedRect(0, TempRect);
7668  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7669  }
7670 
7672  {
7673  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7674 
7675  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7676  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7677  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7678  // rightmost point and the VLoc value of the bottommost point
7679  if(CurrentHLoc >= StartHLoc)
7680  {
7681  CurrentHLoc++;
7682  }
7683  else
7684  {
7685  StartHLoc++;
7686  }
7687  if(CurrentVLoc >= StartVLoc)
7688  {
7689  CurrentVLoc++;
7690  }
7691  else
7692  {
7693  StartVLoc++;
7694  }
7695  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7696  {
7698  }
7699  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7700  {
7702  }
7703  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7704  {
7705  CurrentHLoc = Display->DisplayOffsetH;
7706  }
7707  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7708  {
7709  CurrentVLoc = Display->DisplayOffsetV;
7710  }
7711  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7712  ClearandRebuildRailway(57); // to clear earlier rectangles
7713  Display->PlotDashedRect(2, TempRect);
7714  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7715  }
7716 
7718  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7719  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7720  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7721  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7722  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7723  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7724  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7725  occupies. Clearand... is called finally to clear earlier selection displays.
7726  */
7727  {
7728  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7729  if(X < 0)
7730  {
7731  X = 0; // ensure pointer stays within display area
7732  }
7733  if(X > (MainScreen->Width - 1))
7734  {
7735  X = MainScreen->Width - 1;
7736  }
7737  if(Y < 0)
7738  {
7739  Y = 0;
7740  }
7741  if(Y > (MainScreen->Height - 1))
7742  {
7743  Y = MainScreen->Height - 1;
7744  }
7747  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7748  }
7749 
7751  {
7752  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7754  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7756  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7757 
7758  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7759  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7761  }
7762 
7764  {
7765  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7767  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7769  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7770 
7774  }
7775  }
7776  Utilities->CallLogPop(70);
7777  }
7778  catch(const Exception &e)
7779  {
7780  ErrorLog(22, e.Message);
7781  }
7782 }
7783 
7784 // ---------------------------------------------------------------------------
7785 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7786 {
7787 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7788  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7789  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7790  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7791  selected rectangle.
7792  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7793  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7794  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7795  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7796  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7797  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7798  the selection.
7799  [New] This function can take some time so an houglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7800  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7801  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7802  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7803  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7804  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7805  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7806  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7807  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7808  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7809  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7810  to an arrow.
7811 */
7812  try
7813  {
7814  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7815  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7816  WholeRailwayMoving = false; // added at v2.1.0
7817  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7819  {
7820  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7821  Screen->Cursor = TCursor(-11); // Hourglass;
7822  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7823  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7824 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7825 // rightmost point and the VLoc value of the bottommost point
7826  if(EndHLoc >= StartHLoc)
7827  {
7828  EndHLoc++;
7829  }
7830  else
7831  {
7832  StartHLoc++;
7833  }
7834  if(EndVLoc >= StartVLoc)
7835  {
7836  EndVLoc++;
7837  }
7838  else
7839  {
7840  StartVLoc++;
7841  }
7842  if(StartHLoc >= EndHLoc)
7843  {
7844  SelectRect.left = EndHLoc;
7845  SelectRect.right = StartHLoc;
7846  }
7847  else
7848  {
7849  SelectRect.left = StartHLoc;
7850  SelectRect.right = EndHLoc;
7851  }
7852  if(StartVLoc >= EndVLoc)
7853  {
7854  SelectRect.top = EndVLoc;
7855  SelectRect.bottom = StartVLoc;
7856  }
7857  else
7858  {
7859  SelectRect.top = StartVLoc;
7860  SelectRect.bottom = EndVLoc;
7861  }
7863  {
7865  }
7867  {
7869  }
7870  if(SelectRect.left - Display->DisplayOffsetH < 0)
7871  {
7873  }
7874  if(SelectRect.top - Display->DisplayOffsetV < 0)
7875  {
7877  }
7878  Level2TrackMode = AddTrack; // Level1Mode must be TrackMode
7879  SetLevel2TrackMode(69); // add all track elements so area can be filled with an element, must come before PlotDashedRect as calls Crearand...
7880  Level2TrackMode = TrackSelecting; // reset from AddTrack
7884  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7885  {
7886  SelectionValid = false;
7888  mbLeftDown = false;
7889  Screen->Cursor = TCursor(-2); // Arrow;
7890  Utilities->CallLogPop(71);
7891  return; // no rectangle
7892  }
7893  else
7894  {
7895  ReselectMenuItem->Enabled = false;
7896  CutMenuItem->Enabled = true;
7897  CopyMenuItem->Enabled = true;
7898  FlipMenuItem->Enabled = true;
7899  MirrorMenuItem->Enabled = true;
7900  RotRightMenuItem->Enabled = true;
7901  RotLeftMenuItem->Enabled = true;
7902  RotateMenuItem->Enabled = true;
7903 
7904 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting (dropped at 2.4.0 as all pastes are with attributes)
7905  DeleteMenuItem->Enabled = true;
7906  if(Track->IsTrackFinished())
7907  {
7908  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
7909  }
7910  else
7911  {
7912  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
7913  }
7914  SelectBiDirPrefDirsMenuItem->Visible = false;
7915  CancelSelectionMenuItem->Enabled = true;
7916  // set SelectBitmap
7917  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
7918  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
7919 
7920  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
7921  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
7922  {
7923  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
7924  {
7925  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
7926  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
7927  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
7928  }
7929  }
7930 
7932  TTrackElement TempElement; // default element
7933  bool FoundFlag;
7934  for(int x = SelectRect.left; x < SelectRect.right; x++)
7935  {
7936  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7937  {
7938  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
7939  if(FoundFlag)
7940  {
7941  TempElement = Track->TrackElementAt(440, ATVecPos);
7942  if(TempElement.SpeedTag > 0)
7943  {
7944  Track->SelectPush(TempElement); // don't store erase elements
7945  }
7946  }
7947  }
7948  }
7949  // now store inactive elements
7950  for(int x = SelectRect.left; x < SelectRect.right; x++)
7951  {
7952  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7953  {
7954  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
7955  if(FoundFlag)
7956  {
7957  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
7958  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
7959  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
7960  {
7961  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
7962  Track->SelectPush(TempElement);
7963  }
7964  }
7965  }
7966  }
7967 
7968  // store text items
7969  int LowSelectHPos = SelectRect.left * 16;
7970  int HighSelectHPos = SelectRect.right * 16;
7971  int LowSelectVPos = SelectRect.top * 16;
7972  int HighSelectVPos = SelectRect.bottom * 16;
7973  TextHandler->SelectTextVector.clear();
7974  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
7975  {
7976  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
7977  {
7978  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
7979  HighSelectVPos))
7980  {
7981  // have to create a new TextItem in order to create a new Font object
7982  // BUT: only create new items where they don't appear as named location names
7983  // in SelectVector, since those names shouldn't be copied or pasted.
7984  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
7985  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
7986  bool SelectVectorNamedElement = false;
7987  AnsiString SelectTextString; // new at v2.2.0
7988  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
7989  {
7990  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
7991  {
7992  SelectVectorNamedElement = true;
7993  break;
7994  }
7995  }
7996  if(SelectVectorNamedElement) // changed at v2.2.0
7997  {
7998  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
7999  }
8000  else // new at v2.2.0
8001  {
8002  SelectTextString = TextPtr->TextString;
8003  }
8004  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
8005  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
8006  }
8007  }
8008  }
8009  // store graphic items, but first clear SelectGraphicVector
8010  Track->SelectGraphicVector.clear();
8011  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
8012  {
8013  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
8014  UserGraphicPtr++)
8015  {
8016  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
8017  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
8018  {
8019  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
8020  }
8021  }
8022  }
8023 // new method - direct copying of existing selection so text included
8024  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8025  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8026  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8027  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8028  SelectionValid = true;
8029  }
8030  Screen->Cursor = TCursor(-2); // Arrow;
8031  }
8032 
8034  {
8035  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
8036  Screen->Cursor = TCursor(-11); // Hourglass;
8037 
8038  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
8039  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
8040 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
8041 // rightmost point and the VLoc value of the bottommost point
8042  if(EndHLoc >= StartHLoc)
8043  {
8044  EndHLoc++;
8045  }
8046  else
8047  {
8048  StartHLoc++;
8049  }
8050  if(EndVLoc >= StartVLoc)
8051  {
8052  EndVLoc++;
8053  }
8054  else
8055  {
8056  StartVLoc++;
8057  }
8058  if(StartHLoc >= EndHLoc)
8059  {
8060  SelectRect.left = EndHLoc;
8061  SelectRect.right = StartHLoc;
8062  }
8063  else
8064  {
8065  SelectRect.left = StartHLoc;
8066  SelectRect.right = EndHLoc;
8067  }
8068  if(StartVLoc >= EndVLoc)
8069  {
8070  SelectRect.top = EndVLoc;
8071  SelectRect.bottom = StartVLoc;
8072  }
8073  else
8074  {
8075  SelectRect.top = StartVLoc;
8076  SelectRect.bottom = EndVLoc;
8077  }
8079  {
8081  }
8083  {
8085  }
8086  if(SelectRect.left - Display->DisplayOffsetH < 0)
8087  {
8089  }
8090  if(SelectRect.top - Display->DisplayOffsetV < 0)
8091  {
8093  }
8097  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8098  {
8100  mbLeftDown = false;
8101  Screen->Cursor = TCursor(-2); // Arrow;
8102  Utilities->CallLogPop(1551);
8103  return; // no rectangle
8104  }
8105  else
8106  {
8107  SelectBiDirPrefDirsMenuItem->Enabled = true;
8108  CancelSelectionMenuItem->Enabled = true;
8109  // don't need SelectBitmap for PrefDir selection
8110 
8111  // store active elements in Track->SelectVector, ignore inactive elements
8112  // clear the vector first
8114  TTrackElement TempElement; // default element
8115  bool FoundFlag;
8116  for(int x = SelectRect.left; x < SelectRect.right; x++)
8117  {
8118  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8119  {
8120  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
8121  if(FoundFlag)
8122  {
8123  TempElement = Track->TrackElementAt(729, ATVecPos);
8124  if(TempElement.SpeedTag > 0)
8125  {
8126  Track->SelectPush(TempElement); // don't store erase elements
8127  }
8128  }
8129  }
8130  }
8131  }
8132  Screen->Cursor = TCursor(-2); // Arrow;
8133  }
8134 
8136  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
8137  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
8138  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
8139  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
8140  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
8141  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
8142  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
8143  occupies. Clearand... is called finally to clear earlier selection displays.
8144  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
8145  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
8146  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
8147  */
8148  {
8149  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
8152  }
8153  mbLeftDown = false;
8154  Track->CalcHLocMinEtc(11);
8155  Utilities->CallLogPop(72);
8156  }
8157  catch(const Exception &e)
8158  {
8159  ErrorLog(23, e.Message);
8160  }
8161 }
8162 
8163 // ---------------------------------------------------------------------------
8164 
8165 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
8166 {
8167  try
8168  {
8169  // don't call LogEvent here as would occur too often
8170  // have to allow in zoomout mode
8171  if(ErrorLogCalledFlag)
8172  {
8173  return; // don't continue after an error
8174 
8175  }
8176  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
8177  // put counter outside Clock2 as that may be missed
8178  LCResetCounter++;
8179 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
8180  if(LCResetCounter > 19)
8181  {
8182  LCResetCounter = 0;
8183  }
8185  if(WarningFlashCount > 4)
8186  {
8187  WarningFlashCount = 0;
8188  }
8189  if(WarningFlashCount == 0)
8190  {
8192  }
8193  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
8194  {
8195  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
8196  }
8198  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
8199  {
8200  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
8201  // BaseTime is CurrentDateTime() when operation restarts
8202 
8203 // clock speed multiplier
8204  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
8205  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
8206 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
8207  }
8208  TotalTicks++;
8210  {
8211  MissedTicks++;
8212  Utilities->CallLogPop(774);
8213  return;
8214  }
8215  Utilities->Clock2Stopped = true; // don't allow overlapping calls
8216  ClockTimer2(0);
8217  Utilities->Clock2Stopped = false;
8218  Utilities->CallLogPop(73);
8219  }
8220  catch(const Exception &e)
8221  {
8222  ErrorLog(24, e.Message);
8223  }
8224 }
8225 
8226 // ---------------------------------------------------------------------------
8227 
8228 void TInterface::ClockTimer2(int Caller)
8229 {
8230 // called every 50mSec
8231  try
8232  {
8233  // have to allow in zoomout mode
8234  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
8235 
8236  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
8237  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
8238 
8239 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
8240  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
8241  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
8242 
8243  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
8244 
8245  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
8246  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
8247  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
8248  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
8249 
8250  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
8251  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
8252  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
8253  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
8254  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
8255  {
8256  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
8257  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
8258  if(ClockTimer2Count == 0)
8259  {
8260  RestoreFocusPanel->Visible = true;
8261  RestoreFocusPanel->Enabled = true;
8262  RestoreFocusPanel->BringToFront();
8263  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
8264  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
8265  RestoreFocusPanel->Visible = false;
8266  }
8267  }
8268  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
8269 */
8270 
8271  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
8272  // toggled by 'Ctrl Alt 2' when Interface form has focus
8273 
8274  // set current time
8275  TDateTime Now = TrainController->TTClockTime;
8276 
8277  if(!OAListBox->MouseInClient) // added at v2.7.0 to reset this flag whenever mouse not in OAListBox
8278  {
8280  }
8281  if(!ClipboardChecked)
8282  {
8283  if((Level1Mode == TrackMode) && !SelectionValid & (ClpBrdValid != "RlyClpBrd_Cut") && (ClpBrdValid != "RlyClpBrdCopy"))
8284  // reset the menu for the new app (when !SelectionValid) & don't keep resetting when ClpBrdValid
8285  {
8286  SetTrackModeEditMenu(2); // to reset the menu in case select a new app for pasting
8287  ClipboardChecked = true;
8288  }
8289  }
8293  {
8295  }
8296  if(OperatorActionPanel->Visible)
8297  {
8299  }
8302  {
8303  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
8304  }
8305  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
8307  {
8309  }
8310 // Update Displayed Clock - resets to 0 at 96hours
8312 
8313 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
8314 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
8315 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
8316  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
8317  {
8318  WholeRailwayMoving = false;
8319  Screen->Cursor = TCursor(-2); // Arrow
8320  }
8321 // save session if required
8322  if(SaveSessionFlag)
8323  {
8324  SaveSession(0);
8325  SaveSessionFlag = false;
8326  }
8327 // load session if required
8328  if(LoadSessionFlag)
8329  {
8330  if(ClearEverything(3))
8331  {
8332  LoadSession(0);
8333  }
8334  LoadSessionFlag = false;
8335  }
8336 // check if any LCs need barriers raising
8337 
8339  {
8341  {
8342  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--) // iterate downwards because erase element
8343  {
8344  bool TrainPresent = false;
8346  Track->BarriersDownVector.at(x).VLoc, ConstructRoute->SearchVector, TrainPresent)) // returns true for route (set or being set) or train, and TrainPresent true if train on LC
8347  {
8348  if(TrainPresent)
8349  {
8350  Track->BarriersDownVector.at(x).ReducedTimePenalty = true;
8351 // to allow 3 mins before time penalty starts to clock up, if no train passes then no time allowance
8352  }
8353  }
8354  else
8355  {
8356  if(Track->BarriersDownVector.at(x).TypeOfRoute != 2) // added at v2.6.0 for manual LC operation
8357  {
8358  Track->LCChangeFlag = true;
8360  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
8361  TDateTime TempExcessLCDownTime;
8362  if(Track->BarriersDownVector.at(x).ReducedTimePenalty)
8363  {
8364  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
8365  }
8366  else
8367  {
8368  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
8369  }
8370  if(TempExcessLCDownTime > TDateTime(0))
8371  {
8372  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
8373  }
8374  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
8377  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
8378  Track->ChangingLCVector.push_back(CLC);
8379  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
8380  }
8381  }
8382  }
8383  }
8384  }
8385 // clear LCChangeFlag if no LCs changing
8386  if(Track->ChangingLCVector.empty())
8387  {
8388  Track->LCChangeFlag = false;
8389  }
8390 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
8391 // element it may be removed prior to conversion & cause an error
8392 
8393 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
8394 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
8395 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
8396 // this, it shouldn't interfere with operation.
8398  {
8399  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
8400  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
8401  {
8402  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
8403  {
8404  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
8405  // set & will fail at convert
8407  {
8409  // also don't remove if it links two automatic signal routes (reported by Daniel Gill for Darlington via discord on 13/12/20)
8410  // added at v2.6.1
8411  // note that a train will still remove the route element when it reaches it because of the 3rd condition below, but it will be removed when the train
8412  // is half on the preceding element rather than fully on it, in other cases the train has to be fully on the element because the route only becomes a
8413  // single element at that stage
8414  unsigned int LinkFromTVNumber = Track->TrackElementAt(1007, PDE.GetTrackVectorPosition()).Conn[PDE.GetELinkPos()];
8415  unsigned int LinkToTVNumber = Track->TrackElementAt(1008, PDE.GetTrackVectorPosition()).Conn[PDE.GetXLinkPos()];
8416  int RouteNumber1, RouteNumber2, TrainID; // not used
8417  if((AllRoutes->GetRouteTypeAndNumber(37, LinkFromTVNumber, PDE.GetELinkPos(), RouteNumber1) != TAllRoutes::AutoSigsRoute) ||
8418  (AllRoutes->GetRouteTypeAndNumber(38, LinkToTVNumber, PDE.GetXLinkPos(), RouteNumber2) != TAllRoutes::AutoSigsRoute) ||
8419  (Track->TrackElementAt(1009, LinkFromTVNumber).TrainIDOnElement > -1))
8420  // don't need to test for it being a bridge as then LinkFromTVNumber can't be
8421  // an autosigs route
8422  {
8423  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
8424  ElementRemovedFlag = true;
8425  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
8426  }
8427  }
8428  }
8429  }
8430  if(!Display->ZoomOutFlag && ElementRemovedFlag)
8431  {
8433  }
8434  // if zoomed out ignore, will display correctly when zoom in
8435  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
8436  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
8437  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
8438  }
8439 // stop clock if hover over a warning
8440  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
8441  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
8442  && OutputLog1->Caption != "";
8443  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
8444  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
8445  && OutputLog2->Caption != "";
8446  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
8447  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
8448  && OutputLog3->Caption != "";
8449  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
8450  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
8451  && OutputLog4->Caption != "";
8452  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
8453  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
8454  && OutputLog5->Caption != "";
8455  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
8456  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
8457  && OutputLog6->Caption != "";
8458  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
8459  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
8460  && OutputLog7->Caption != "";
8461  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
8462  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
8463  && OutputLog8->Caption != "";
8464  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
8465  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
8466  && OutputLog9->Caption != "";
8467  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
8468  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
8469  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
8470 
8471  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
8472  {
8473  if(!WarningHover)
8474  {
8475  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
8477  WarningHover = true;
8478  }
8479  }
8480  else if(WarningHover)
8481  {
8482  WarningHover = false;
8483  TrainController->BaseTime = TDateTime::CurrentDateTime();
8485  }
8486 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
8487  if(DevelopmentPanel->Visible)
8488  {
8489  int Position;
8490  TTrackElement TrackElement;
8491  AnsiString Type[15] =
8492  {
8493  "Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
8494  "Parapet", "NamedNonStationLocation", "Erase"
8495  };
8496 
8497  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
8498  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
8499  int HLoc, VLoc;
8500  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
8501  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
8502  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
8503  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
8504  {
8505  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
8506  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
8507  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
8508  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
8509  TrackElement.ActiveTrackElementName;
8510 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
8511  }
8512  }
8513  if(Level1Mode == TimetableMode)
8514  {
8515 /* These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
8516 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version after v2.4.3 for details.
8517 
8518 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
8519 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
8520 the entry that the mouse is now on rather than the one that was chosen.
8521 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
8522 */
8523  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0))
8524  // high order bit set to 1 when button down, so arithmetically it is negative
8525  {
8526  // TTCurrentEntryPtr == 0 when create a timetable
8527  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
8528  }
8529  if(AnyTTKeyFlagSet()) // true if any of the below flags set
8530  {
8531  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; // reset it to the value before the key press changes it (see FormKeyDown)
8532  }
8534  {
8535  PreviousTTEntryButton->Click();
8536  SetTopIndex(0);
8537  PreviousTTEntryKeyFlag = false;
8538  }
8539  else if(NextTTEntryKeyFlag)
8540  {
8541  NextTTEntryButton->Click();
8542  SetTopIndex(1);
8543  NextTTEntryKeyFlag = false;
8544  }
8545  else if(MoveTTEntryUpKeyFlag)
8546  {
8547  MoveTTEntryUpButton->Click();
8548  SetTopIndex(2);
8549  MoveTTEntryUpKeyFlag = false;
8550  }
8551  else if(MoveTTEntryDownKeyFlag)
8552  {
8553  MoveTTEntryDownButton->Click();
8554  SetTopIndex(3);
8555  MoveTTEntryDownKeyFlag = false;
8556  }
8557  else if(CopyTTEntryKeyFlag)
8558  {
8559  CopyTTEntryButton->Click();
8560  SetTopIndex(4);
8561  CopyTTEntryKeyFlag = false;
8562  }
8563  else if(CutTTEntryKeyFlag)
8564  {
8565  CutTTEntryButton->Click();
8566  SetTopIndex(5);
8567  CutTTEntryKeyFlag = false;
8568  }
8569  else if(PasteTTEntryKeyFlag)
8570  {
8571  PasteTTEntryButton->Click();
8572  SetTopIndex(6);
8573  PasteTTEntryKeyFlag = false;
8574  }
8575  else if(DeleteTTEntryKeyFlag)
8576  {
8577  DeleteTTEntryButton->Click();
8578  SetTopIndex(7);
8579  DeleteTTEntryKeyFlag = false;
8580  }
8581  else if(NewTTEntryKeyFlag)
8582  {
8583  NewTTEntryButton->Click();
8584  SetTopIndex(8);
8585  NewTTEntryKeyFlag = false;
8586  }
8587  else if(AZOrderKeyFlag)
8588  {
8589  AZOrderButton->Click();
8590  SetTopIndex(9);
8591  AZOrderKeyFlag = false;
8592  }
8594  {
8595  TTServiceSyntaxCheckButton->Click();
8596  SetTopIndex(12);
8598  }
8599  else if(ValidateTimetableKeyFlag)
8600  {
8601  ValidateTimetableButton->Click();
8602  SetTopIndex(13);
8603  ValidateTimetableKeyFlag = false;
8604  }
8605  else if(SaveTTKeyFlag)
8606  {
8607  SaveTTButton->Click();
8608  SetTopIndex(14);
8609  SaveTTKeyFlag = false;
8610  }
8611  else if(SaveTTAsKeyFlag)
8612  {
8613  SaveTTAsButton->Click();
8614  SetTopIndex(15);
8615  SaveTTAsKeyFlag = false;
8616  }
8617  else if(RestoreTTKeyFlag)
8618  {
8619  RestoreTTButton->Click();
8620  SetTopIndex(16);
8621  RestoreTTKeyFlag = false;
8622  }
8623  else if(ExportTTKeyFlag)
8624  {
8625  ExportTTButton->Click();
8626  SetTopIndex(17);
8627  ExportTTKeyFlag = false;
8628  }
8629  else if(ConflictAnalysisKeyFlag)
8630  {
8631  ConflictAnalysisButton->Click();
8632  SetTopIndex(18);
8633  ConflictAnalysisKeyFlag = false;
8634  }
8635 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
8636  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
8637  {
8639  }
8640  else
8641  {
8643  }
8644  }
8645 // set cursor
8647  {
8648  if(!TempCursorSet)
8649  {
8650  TempCursor = Screen->Cursor;
8651  TempCursorSet = true;
8652  }
8653  Screen->Cursor = TCursor(-11); // Hourglass
8654  }
8655  else
8656  {
8657  if(TempCursorSet)
8658  {
8659  Screen->Cursor = TempCursor;
8660  TempCursorSet = false;
8661  }
8662  }
8663  if(Level2OperMode == Operating)
8664  {
8665  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8666  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8668  {
8669  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8670  }
8671  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8672  }
8673 
8674  else if(Level2OperMode == Paused) // added after v2.4.3 to show actions due after a session file reloaded
8675  {
8677  {
8678  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8679  {
8681  }
8684  }
8685  }
8686 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8687 // by examining Flash
8688  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8689  {
8691  }
8692 // Deal with any flashing graphics
8694  {
8695  FlashingGraphics(0, Now); // only call when WarningFlash changes
8696  if(Level1Mode == OperMode)
8697  {
8698  if(WarningFlash)
8699  {
8701  {
8702  CrashImage->Visible = true;
8703  }
8705  {
8706  DerailImage->Visible = true;
8707  }
8709  {
8710  SPADImage->Visible = true;
8711  }
8713  {
8714  TrainFailedImage->Visible = true;
8715  }
8717  {
8718  CallOnImage->Visible = true;
8719  }
8721  {
8722  SignalStopImage->Visible = true;
8723  }
8725  {
8726  BufferAttentionImage->Visible = true;
8727  }
8728  }
8729  else
8730  {
8731  CrashImage->Visible = false;
8732  DerailImage->Visible = false;
8733  SPADImage->Visible = false;
8734  TrainFailedImage->Visible = false;
8735  CallOnImage->Visible = false;
8736  SignalStopImage->Visible = false;
8737  BufferAttentionImage->Visible = false;
8738  }
8739  }
8740  else
8741  {
8742  CrashImage->Visible = false;
8743  DerailImage->Visible = false;
8744  SPADImage->Visible = false;
8745  TrainFailedImage->Visible = false;
8746  CallOnImage->Visible = false;
8747  SignalStopImage->Visible = false;
8748  BufferAttentionImage->Visible = false;
8749  }
8750  } // if(WarningFlashCount == 0)
8751 
8752  // set buttons etc as appropriate
8754  // if forced route cancellation flag set redisplay to clear the cancelled route
8756  {
8758  AllRoutes->RebuildRailwayFlag = false;
8759  }
8760  // deal with approach locking
8762  // deal with ContinuationAutoSigList
8764  // FloatingLabel function
8765  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8766  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8767  {
8768  TrackTrainFloat(0);
8769  }
8770  else
8771  {
8772  FloatingPanel->Visible = false;
8773  }
8774  // PerformanceLog check function
8775 /*
8776  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8777  {
8778  PerformancePanel->Visible = false;
8779  }
8780  else
8781  {
8782 */
8784  {
8785  PerformancePanel->Visible = true;
8786  }
8787  else
8788  {
8789  PerformancePanel->Visible = false;
8790  }
8792  {
8793  OperatorActionPanel->Visible = true;
8794  }
8795  else
8796  {
8797  OperatorActionPanel->Visible = false;
8798  }
8799 // }
8800 
8801  // check if a moving train is present on a route-under-construction start element & cancel it if so
8802  if(RouteMode == RouteContinuing)
8803  {
8804  bool FoundFlag;
8805  int RouteStartVecPos;
8806  if(AutoSigsFlag)
8807  {
8809  FoundFlag);
8810  }
8811  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
8812  {
8813  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
8814  FoundFlag);
8815  }
8816  else
8817  {
8819  FoundFlag);
8820  }
8821  if(FoundFlag && (RouteStartVecPos > -1))
8822  {
8823  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8824  if(TrackElement.TrainIDOnElement > -1)
8825  {
8826  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8827  {
8829  // replot train as above erases the front element of the train
8831  }
8832  }
8833  }
8834  }
8835  Utilities->CallLogPop(81);
8836  }
8837  catch(const Exception &e)
8838  {
8839  ErrorLog(25, e.Message);
8840  }
8841 }
8842 
8843 // ---------------------------------------------------------------------------
8844 
8845 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
8846 {
8847  try
8848  {
8849  TrainController->LogEvent("CallingOnButtonClick");
8850  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
8851  if(CallingOnButton->Down)
8852  {
8853  // CallingOnButton->Down = true;
8854  InfoPanel->Visible = true;
8855  InfoPanel->Caption = "CALLING ON: Select signal for call on";
8856  }
8857  else
8858  {
8859  // CallingOnButton->Down = false;
8861  }
8862  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
8863  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
8864  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
8865  CallingOnButton->Enabled = false;
8866 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
8867  Utilities->CallLogPop(82);
8868  }
8869  catch(const Exception &e)
8870  {
8871  ErrorLog(26, e.Message);
8872  }
8873 }
8874 
8875 // ---------------------------------------------------------------------------
8876 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
8877 {
8878  try
8879  {
8880  // have to allow in zoomout mode
8881  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8882  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8883  Screen->Cursor = TCursor(-11); // Hourglass;
8884  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8885  if(!Display->ZoomOutFlag)
8886  {
8887  if(CtrlKey)
8888  {
8889  Display->DisplayOffsetH -= 2;
8890  }
8891  else if(ShiftKey)
8892  {
8894  }
8895  else
8896  {
8898  }
8901  {
8903  }
8904  }
8905  else
8906  {
8907  if(CtrlKey)
8908  {
8910  }
8911  else if(ShiftKey)
8912  {
8914  }
8915  else
8916  {
8918  }
8919  Display->ClearDisplay(0);
8922  {
8923  Track->PlotSmallRedGap(0);
8924  }
8925  }
8926  ScreenLeftButton->Enabled = true;
8927  Screen->Cursor = TCursor(-2); // Arrow
8928  Utilities->CallLogPop(83);
8929  }
8930  catch(const Exception &e)
8931  {
8932  ErrorLog(27, e.Message);
8933  }
8934 }
8935 // ---------------------------------------------------------------------------
8936 
8937 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
8938 {
8939  try
8940  {
8941  // have to allow in zoomout mode
8942  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8943  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8944  Screen->Cursor = TCursor(-11); // Hourglass;
8945  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8946  if(!Display->ZoomOutFlag)
8947  {
8948  if(CtrlKey)
8949  {
8950  Display->DisplayOffsetH += 2;
8951  }
8952  else if(ShiftKey)
8953  {
8955  }
8956  else
8957  {
8959  }
8962  {
8964  }
8965  }
8966  else
8967  {
8968  if(CtrlKey)
8969  {
8971  }
8972  else if(ShiftKey)
8973  {
8975  }
8976  else
8977  {
8979  }
8980  Display->ClearDisplay(1);
8983  {
8984  Track->PlotSmallRedGap(1);
8985  }
8986  }
8987  ScreenRightButton->Enabled = true;
8988  Screen->Cursor = TCursor(-2); // Arrow
8989  Utilities->CallLogPop(84);
8990  }
8991  catch(const Exception &e)
8992  {
8993  ErrorLog(28, e.Message);
8994  }
8995 }
8996 // ---------------------------------------------------------------------------
8997 
8998 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
8999 {
9000  try
9001  {
9002  // have to allow in zoomout mode
9003  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9004  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9005  Screen->Cursor = TCursor(-11); // Hourglass;
9006  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9007  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
9008  if(!Display->ZoomOutFlag)
9009  {
9010  if(CtrlKey)
9011  {
9012  Display->DisplayOffsetV += 2;
9013  }
9014  else if(ShiftKey)
9015  {
9017  }
9018  else
9019  {
9021  }
9024  {
9026  }
9027  }
9028  else
9029  {
9030  if(CtrlKey)
9031  {
9033  }
9034  else if(ShiftKey)
9035  {
9037  }
9038  else
9039  {
9041  }
9042  Display->ClearDisplay(2);
9045  {
9046  Track->PlotSmallRedGap(2);
9047  }
9048  }
9049  ScreenDownButton->Enabled = true;
9050  Screen->Cursor = TCursor(-2); // Arrow
9051  Utilities->CallLogPop(85);
9052  }
9053  catch(const Exception &e)
9054  {
9055  ErrorLog(29, e.Message);
9056  }
9057 }
9058 // ---------------------------------------------------------------------------
9059 
9060 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
9061 {
9062  try
9063  {
9064  // have to allow in zoomout mode
9065  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9066  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9067  Screen->Cursor = TCursor(-11); // Hourglass;
9068  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9069  if(!Display->ZoomOutFlag)
9070  {
9071  if(CtrlKey)
9072  {
9073  Display->DisplayOffsetV -= 2;
9074  }
9075  else if(ShiftKey)
9076  {
9078  }
9079  else
9080  {
9082  }
9085  {
9087  }
9088  }
9089  else
9090  {
9091  if(CtrlKey)
9092  {
9094  }
9095  else if(ShiftKey)
9096  {
9098  }
9099  else
9100  {
9102  }
9103  Display->ClearDisplay(3);
9106  {
9107  Track->PlotSmallRedGap(3);
9108  }
9109  }
9110  ScreenUpButton->Enabled = true;
9111  Screen->Cursor = TCursor(-2); // Arrow
9112  Utilities->CallLogPop(86);
9113  }
9114  catch(const Exception &e)
9115  {
9116  ErrorLog(30, e.Message);
9117  }
9118 }
9119 // ---------------------------------------------------------------------------
9120 
9121 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
9122 {
9123  try
9124  {
9125  // have to allow in zoomout mode
9126  TrainController->LogEvent("ZoomButtonClick");
9127  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
9128  Screen->Cursor = TCursor(-11); // Hourglass;
9129  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9130  if(Display->ZoomOutFlag) // i.e resume zoomed in view
9131  {
9132  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
9133 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
9134  if(Level1Mode == BaseMode)
9135  {
9136  InfoPanel->Visible = false; // reset infopanel in case not set later
9137  InfoPanel->Caption = "";
9138  SetLevel1Mode(18);
9139  }
9140  else if(Level1Mode == TrackMode)
9141  {
9142  InfoPanel->Visible = false; // reset infopanel in case not set later
9143  InfoPanel->Caption = "";
9144  // set edit menu items
9146  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
9147  }
9148  else if(Level1Mode == PrefDirMode)
9149  {
9151  {
9152  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
9153  }
9154  else
9155  {
9156  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
9157  }
9158  }
9159 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
9160 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
9161  else if(Level1Mode == TimetableMode)
9162  {
9163  InfoPanel->Visible = false;
9164  }
9165  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
9166  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
9167  {
9168  OperateButton->Enabled = true;
9169  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
9170  ExitOperationButton->Enabled = true;
9172  }
9173  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
9174  {
9175  OperateButton->Enabled = true;
9176  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9177  ExitOperationButton->Enabled = true;
9178  TTClockAdjButton->Enabled = true;
9181  }
9182  else if(Level2OperMode == PreStart)
9183  {
9184  OperateButton->Enabled = true;
9185  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9186  ExitOperationButton->Enabled = true;
9187  TTClockAdjButton->Enabled = true;
9189  }
9190  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
9192  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
9193  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
9194  }
9195  else // set zoomed out view
9196  {
9197  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
9198  Display->ZoomOutFlag = true;
9200  FileMenu->Enabled = false;
9201  ModeMenu->Enabled = false;
9202  EditMenu->Enabled = false;
9203  TextBox->Visible = false;
9204  LocationNameTextBox->Visible = false;
9205  TTClockAdjButton->Enabled = false;
9206 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
9207  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9208  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
9209 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
9210  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
9211  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
9212  if((LeftExcess > 0) && (RightExcess > 0))
9213  {
9214  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
9215  }
9216  else if((LeftExcess > 0) && (RightExcess <= 0))
9217  {
9218  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
9219  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
9220  }
9221  else if((LeftExcess <= 0) && (RightExcess > 0))
9222  {
9223  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
9224  }
9225  else
9226  {
9227  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
9228 
9229  }
9230  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
9231  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
9232  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
9233  if((TopExcess > 0) && (BotExcess > 0))
9234  {
9235  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
9236  }
9237  else if((TopExcess > 0) && (BotExcess <= 0))
9238  {
9239  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
9240  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
9241  }
9242  else if((TopExcess <= 0) && (BotExcess > 0))
9243  {
9244  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
9245  }
9246  else
9247  {
9248  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
9249 
9250  }
9251  Display->ClearDisplay(4);
9255  {
9256  Track->PlotSmallRedGap(4);
9257  }
9258  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
9259  }
9260  Screen->Cursor = TCursor(-2); // Arrow
9261  ZoomButton->Enabled = true; // restore, see above
9262  Utilities->CallLogPop(87);
9263  }
9264  catch(const Exception &e)
9265  {
9266  ErrorLog(31, e.Message);
9267  }
9268 }
9269 // ---------------------------------------------------------------------------
9270 
9271 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
9272 {
9273  try
9274  {
9275  // have to allow in zoomout mode
9276  TrainController->LogEvent("HomeButtonClick");
9277  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
9278  Screen->Cursor = TCursor(-11); // Hourglass;
9279  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9280  if(!Display->ZoomOutFlag) // zoomed in mode
9281  {
9282  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
9286  {
9288  }
9289  }
9290  else
9291  {
9292  // zoomed out mode
9293  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9294  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
9296  Display->ClearDisplay(9);
9299  {
9300  Track->PlotSmallRedGap(5);
9301  }
9302  }
9303  Screen->Cursor = TCursor(-2); // Arrow
9304  HomeButton->Enabled = true; // restore, see above
9305  Utilities->CallLogPop(88);
9306  }
9307  catch(const Exception &e)
9308  {
9309  ErrorLog(32, e.Message);
9310  }
9311 }
9312 
9313 // ---------------------------------------------------------------------------
9314 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
9315 {
9316  try
9317  {
9318  TrainController->LogEvent("NewHomeButtonClick");
9319  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
9320  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9321  if(!Display->ZoomOutFlag) // zoomed in mode
9322  {
9325  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
9326  }
9327  else
9328  {
9331  }
9332  Utilities->CallLogPop(1188);
9333  NewHomeButton->Enabled = true; // restore, see above
9334  }
9335  catch(const Exception &e)
9336  {
9337  ErrorLog(174, e.Message);
9338  }
9339 }
9340 
9341 // ---------------------------------------------------------------------------
9342 void __fastcall TInterface::EditMenuClick(TObject *Sender)
9343 // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
9344 {
9345  try
9346  {
9347  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
9348  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
9349  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
9350  }
9351  catch(const Exception &e)
9352  {
9353  ErrorLog(196, e.Message);
9354  }
9355 }
9356 
9357 // ---------------------------------------------------------------------------
9358 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
9359 {
9360 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
9361  try
9362  {
9363  TrainController->LogEvent("SelectMenuItemClick");
9364  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
9365  if(Level1Mode == TrackMode)
9366  {
9367  SelectionValid = false;
9369  SetLevel2TrackMode(34);
9371  {
9372  ShowMessage("Please be aware when pasting that anything inside the pasted area will be overwritten.\n\nThis warning will not be shown again.");
9373  PasteWarningSentFlag = true;
9374  }
9375  }
9376  else if(Level1Mode == PrefDirMode)
9377  {
9380  }
9381  Utilities->CallLogPop(1189);
9382  }
9383  catch(const Exception &e)
9384  {
9385  ErrorLog(145, e.Message);
9386  }
9387 }
9388 
9389 // ---------------------------------------------------------------------------
9390 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
9391 {
9392  try
9393  {
9394  TrainController->LogEvent("ReselectMenuItemClick");
9395  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
9396  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
9397  {
9398  Utilities->CallLogPop(1424);
9399  return;
9400  }
9401  int TLHCH = SelectBitmapHLoc;
9402  int TLHCV = SelectBitmapVLoc;
9403  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
9404  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
9405  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
9406  SelectRect = NewSelectRect;
9408  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
9409  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
9410  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
9411  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
9412  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
9413 
9414  SelectionValid = true;
9415  ReselectMenuItem->Enabled = false;
9416  CutMenuItem->Enabled = true;
9417  CopyMenuItem->Enabled = true;
9418  FlipMenuItem->Enabled = true;
9419  MirrorMenuItem->Enabled = true;
9420  RotRightMenuItem->Enabled = true;
9421  RotLeftMenuItem->Enabled = true;
9422  RotateMenuItem->Enabled = true;
9423  PasteMenuItem->Enabled = false;
9424  DeleteMenuItem->Enabled = true;
9425  if(Track->IsTrackFinished())
9426  {
9427  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
9428  }
9429  else
9430  {
9431  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
9432  }
9433  SelectBiDirPrefDirsMenuItem->Visible = false;
9434  CancelSelectionMenuItem->Enabled = true;
9435  mbLeftDown = false;
9436  // Level1Mode = TrackMode;
9437  // SetLevel1Mode(68);
9439  SetLevel2TrackMode(47);
9440  Utilities->CallLogPop(1425);
9441  }
9442  catch(const Exception &e)
9443  {
9444  ErrorLog(146, e.Message);
9445  }
9446 }
9447 
9448 // ---------------------------------------------------------------------------
9449 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
9450 {
9451  try
9452  {
9453  TrainController->LogEvent("CutMenuItemClick");
9454  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
9455  // Level1Mode = TrackMode;
9456  // SetLevel1Mode(69);
9457  CopySelected = false; // new at v2.8.0
9458  LoadClipboard(0); // new at v2.8.0
9460  SetLevel2TrackMode(35);
9461  Utilities->CallLogPop(1190);
9462  }
9463  catch(const Exception &e)
9464  {
9465  ErrorLog(147, e.Message);
9466  }
9467 }
9468 // ---------------------------------------------------------------------------
9469 
9470 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
9471 {
9472  try
9473  {
9474  TrainController->LogEvent("CopyMenuItemClick");
9475  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
9476  // Level1Mode = TrackMode;
9477  // SetLevel1Mode(70);
9478  CopySelected = true; // new at v2.8.0
9479  LoadClipboard(1); // new at v2.8.0
9481  SetLevel2TrackMode(36);
9482  Utilities->CallLogPop(1191);
9483  }
9484  catch(const Exception &e)
9485  {
9486  ErrorLog(148, e.Message);
9487  }
9488 }
9489 
9490 // ---------------------------------------------------------------------------
9491 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
9492 {
9493  try
9494  {
9495  TrainController->LogEvent("FlipMenuItemClick");
9496  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
9497  // reset values in SelectVector
9498  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9499  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9500  {
9501  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
9502  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
9503  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
9504  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
9505  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
9506  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
9507  int HLoc = Track->SelectVectorAt(7, x).HLoc;
9509  TE.VLoc = VLoc;
9510  TE.HLoc = HLoc;
9511 
9512  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9514  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
9515  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
9518  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
9519  Track->SelectVectorAt(26, x) = TE;
9520  }
9521  // reset values in SelectTextVector
9522  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
9523  {
9525  // also subtract font height, brings position approximately right
9526  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9527  }
9528  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9529  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9530  {
9531  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9532  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9533  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9534  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9535  }
9537  SetLevel2TrackMode(48);
9538  Utilities->CallLogPop(1426);
9539  }
9540  catch(const Exception &e)
9541  {
9542  ErrorLog(149, e.Message);
9543  }
9544 }
9545 
9546 // ---------------------------------------------------------------------------
9547 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
9548 {
9549  try
9550  {
9551  TrainController->LogEvent("MirrorMenuItemClick");
9552  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
9553  // reset values in SelectVector
9554  int HorSum = SelectRect.left + SelectRect.right - 1;
9555  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9556  {
9557  // See note above for FlipMenuItem relating to mods for v2.2.0
9558  int VLoc = Track->SelectVectorAt(22, x).VLoc;
9559  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
9561  TE.VLoc = VLoc;
9562  TE.HLoc = HLoc;
9563 
9564  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9566  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
9567  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
9570  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
9571 
9572 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
9573  Track->SelectVectorAt(30, x) = TE;
9574 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
9575 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
9576  }
9577  // reset values in SelectTextVector
9578  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
9579  {
9581  // also subtract half font height for each letter of text, brings position approximately right
9582  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9583  }
9584  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9585  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9586  {
9587  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9588  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9589  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9590  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9591  {
9592  LeftPosAfterMirror = SelectRect.left * 16;
9593  }
9594  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9595  }
9597  SetLevel2TrackMode(49);
9598  Utilities->CallLogPop(1427);
9599  }
9600  catch(const Exception &e)
9601  {
9602  ErrorLog(150, e.Message);
9603  }
9604 }
9605 
9606 // ---------------------------------------------------------------------------
9607 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
9608 {
9609  try
9610  {
9611  TrainController->LogEvent("Rotate180MenuItemClick");
9612  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
9613  // reset values in SelectVector
9614  int HorSum = SelectRect.left + SelectRect.right - 1;
9615  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9616  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9617  {
9618  // See note above for FlipMenuItem relating to mods for v2.2.0
9619  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
9620  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
9622  TE.VLoc = VLoc;
9623  TE.HLoc = HLoc;
9624 
9625  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9627  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
9628  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
9631  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
9632 
9633 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
9634  Track->SelectVectorAt(34, x) = TE;
9635 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
9636 // TempEl.HLoc = HorSum - TempEl.HLoc;
9637 // TempEl.VLoc = VerSum - TempEl.VLoc;
9638 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
9639  }
9640  // reset values in SelectTextVector
9641  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
9642  {
9644  // also subtract half font height for each letter of text, brings position approximately right horizontally
9645  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9646  // also subtract font height, brings position approximately right vertically
9647  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9648  }
9649  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9650  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9651  {
9652  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9653  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9654  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9655  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
9656  {
9657  TopPosAfterFlip = SelectRect.top * 16;
9658  }
9659  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9660  }
9661  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9662  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9663  {
9664  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9665  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9666  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9667  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9668  {
9669  LeftPosAfterMirror = SelectRect.left * 16;
9670  }
9671  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9672  }
9673  // Level1Mode = TrackMode;
9674  // SetLevel1Mode(73);
9676  SetLevel2TrackMode(50);
9677  Utilities->CallLogPop(1435);
9678  }
9679  catch(const Exception &e)
9680  {
9681  ErrorLog(151, e.Message);
9682  }
9683 }
9684 // ---------------------------------------------------------------------------
9685 
9686 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
9687 {
9688  try
9689  {
9690  TrainController->LogEvent("RotateRight90MenuItemClick");
9691  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRight90MenuItemClick");
9692  Screen->Cursor = TCursor(-11); // Hourglass
9693  // check first if a square and if not give message & quit
9694  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9695  {
9696  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9697  int VertSize = SelectRect.bottom - SelectRect.top;
9698  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9699  {
9700  // use right hand vertical & make square to left of that
9701  SelectRect.left = SelectRect.right - VertSize;
9702  }
9703  else
9704  {
9705  SelectRect.right = SelectRect.left + VertSize;
9706  }
9709  int button = Application->MessageBox
9710  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9711  L"Left click and hold here to move this message box", MB_OKCANCEL);
9712  if(button == IDCANCEL)
9713  {
9714  ResetSelectRect();
9715  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9716  SetLevel1Mode(133);
9718  SetLevel2TrackMode(59);
9720  Screen->Cursor = TCursor(-2); // Arrow
9721  Utilities->CallLogPop(2121);
9722  return;
9723  }
9724  }
9725  // set SelectBitmap (only need the dimensions here as not moving the selection)
9728  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9729  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9730  // store track elements and text in select vectors
9732  TTrackElement TempElement; // default element
9733  bool FoundFlag;
9734  for(int x = SelectRect.left; x < SelectRect.right; x++)
9735  {
9736  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9737  {
9738  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
9739  if(FoundFlag)
9740  {
9741  TempElement = Track->TrackElementAt(959, ATVecPos);
9742  if(TempElement.SpeedTag > 0)
9743  {
9744  Track->SelectPush(TempElement);
9745  }
9746  }
9747  }
9748  }
9749  // now store inactive elements
9750  for(int x = SelectRect.left; x < SelectRect.right; x++)
9751  {
9752  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9753  {
9754  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
9755  if(FoundFlag)
9756  {
9757  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
9758  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9759  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9760  {
9761  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
9762  Track->SelectPush(TempElement);
9763  }
9764  }
9765  }
9766  }
9767  // store text items
9768  int LowSelectHPos = SelectRect.left * 16;
9769  int HighSelectHPos = SelectRect.right * 16;
9770  int LowSelectVPos = SelectRect.top * 16;
9771  int HighSelectVPos = SelectRect.bottom * 16;
9772  TextHandler->SelectTextVector.clear();
9773  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9774  {
9775  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9776  {
9777  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9778  {
9779  // have to create a new TextItem in order to create a new Font object
9780  // BUT: only create new items where they don't appear as named location names
9781  // in SelectVector, since those names shouldn't be copied or pasted.
9782  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9783  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9784  bool SelectVectorNamedElement = false;
9785  AnsiString SelectTextString; // new at v2.2.0
9786  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9787  {
9788  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9789  {
9790  SelectVectorNamedElement = true;
9791  break;
9792  }
9793  }
9794  if(SelectVectorNamedElement) // changed at v2.2.0
9795  {
9796  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9797  }
9798  else // new at v2.2.0
9799  {
9800  SelectTextString = TextPtr->TextString;
9801  }
9802  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9803  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9804  }
9805  }
9806  }
9807  // store graphic items, but first clear SelectGraphicVector
9808  Track->SelectGraphicVector.clear();
9809  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9810  {
9811  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9812  UserGraphicPtr++)
9813  {
9814  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9815  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9816  {
9817  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9818  }
9819  }
9820  }
9821  // now transform the H & V for rh rotate
9822  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9823  {
9824  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
9825  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
9827  TE.VLoc = VLoc;
9828  TE.HLoc = HLoc;
9829 
9830  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9832  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
9833  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
9836  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
9837  Track->SelectVectorAt(65, x) = TE;
9838  }
9839  // reset values in SelectTextVector
9840  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
9841  {
9842 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9843 // & if a lot then some will extend beyond the selection
9845  // also subtract half font height for each letter of text, brings position approximately right horizontally
9846  TextItem->HPos = (SelectRect.left) * 16;
9847  TextItem->VPos = (SelectRect.top + x) * 16;
9848  }
9849  // reset values in SelectGraphicVector
9850  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9851  {
9852  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9853  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9854  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
9855  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
9856  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9857  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9858  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9859  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9860  }
9861  Screen->Cursor = TCursor(-2); // Arrow
9863  SetLevel2TrackMode(60);
9864  Utilities->CallLogPop(2122);
9865  }
9866  catch(const Exception &e)
9867  {
9868  ErrorLog(205, e.Message);
9869  }
9870 }
9871 
9872 // ---------------------------------------------------------------------------
9873 
9874 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
9875 {
9876  try
9877  {
9878  TrainController->LogEvent("RotateLeft90MenuItemClick");
9879  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeft90MenuItemClick");
9880  Screen->Cursor = TCursor(-11); // Hourglass;
9881  // check first if a square and if not give message & quit
9882  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9883  {
9884  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9885  int VertSize = SelectRect.bottom - SelectRect.top;
9886  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9887  {
9888  // use right hand vertical & make square to left of that
9889  SelectRect.left = SelectRect.right - VertSize;
9890  }
9891  else
9892  {
9893  SelectRect.right = SelectRect.left + VertSize;
9894  }
9897  int button = Application->MessageBox
9898  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9899  L"Left click and hold here to move this message box", MB_OKCANCEL);
9900  if(button == IDCANCEL)
9901  {
9902  ResetSelectRect();
9903  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9904  SetLevel1Mode(134);
9906  SetLevel2TrackMode(61);
9908  Screen->Cursor = TCursor(-2); // Arrow
9909  Utilities->CallLogPop(2123);
9910  return;
9911  }
9912  }
9913  // set SelectBitmap (only need the dimensions here as not moving the selection)
9916  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9917  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9918  // store track elements and text in select vectors
9920  TTrackElement TempElement; // default element
9921  bool FoundFlag;
9922  for(int x = SelectRect.left; x < SelectRect.right; x++)
9923  {
9924  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9925  {
9926  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
9927  if(FoundFlag)
9928  {
9929  TempElement = Track->TrackElementAt(960, ATVecPos);
9930  if(TempElement.SpeedTag > 0)
9931  {
9932  Track->SelectPush(TempElement);
9933  }
9934  }
9935  }
9936  }
9937  // now store inactive elements
9938  for(int x = SelectRect.left; x < SelectRect.right; x++)
9939  {
9940  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9941  {
9942  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
9943  if(FoundFlag)
9944  {
9945  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
9946  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9947  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9948  {
9949  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
9950  Track->SelectPush(TempElement);
9951  }
9952  }
9953  }
9954  }
9955  // store text items
9956  int LowSelectHPos = SelectRect.left * 16;
9957  int HighSelectHPos = SelectRect.right * 16;
9958  int LowSelectVPos = SelectRect.top * 16;
9959  int HighSelectVPos = SelectRect.bottom * 16;
9960  TextHandler->SelectTextVector.clear();
9961  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9962  {
9963  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9964  {
9965  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9966  {
9967  // have to create a new TextItem in order to create a new Font object
9968  // BUT: only create new items where they don't appear as named location names
9969  // in SelectVector, since those names shouldn't be copied or pasted.
9970  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9971  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9972  bool SelectVectorNamedElement = false;
9973  AnsiString SelectTextString; // new at v2.2.0
9974  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9975  {
9976  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9977  {
9978  SelectVectorNamedElement = true;
9979  break;
9980  }
9981  }
9982  if(SelectVectorNamedElement) // changed at v2.2.0
9983  {
9984  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9985  }
9986  else // new at v2.2.0
9987  {
9988  SelectTextString = TextPtr->TextString;
9989  }
9990  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9991  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9992  }
9993  }
9994  }
9995  // store graphic items, but first clear SelectGraphicVector
9996  Track->SelectGraphicVector.clear();
9997  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9998  {
9999  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10000  UserGraphicPtr++)
10001  {
10002  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10003  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10004  {
10005  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10006  }
10007  }
10008  }
10009  // now transform the H & V for lh rotate
10010  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10011  {
10012  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
10013  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
10015  TE.VLoc = VLoc;
10016  TE.HLoc = HLoc;
10017 
10018  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10020  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
10021  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
10024  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
10025  Track->SelectVectorAt(73, x) = TE;
10026  }
10027  // reset values in SelectTextVector
10028  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
10029  {
10030 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10031 // & if a lot then some will extend beyond the selection
10033  // also subtract half font height for each letter of text, brings position approximately right horizontally
10034  TextItem->HPos = (SelectRect.left) * 16;
10035  TextItem->VPos = (SelectRect.top + x) * 16;
10036  }
10037  // reset values in SelectGraphicVector
10038  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10039  {
10040  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10041  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10042  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
10043  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
10044  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10045  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10046  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10047  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10048  }
10049  Screen->Cursor = TCursor(-2); // Arrow
10051  SetLevel2TrackMode(62);
10052  Utilities->CallLogPop(2124);
10053  }
10054  catch(const Exception &e)
10055  {
10056  ErrorLog(206, e.Message);
10057  }
10058 }
10059 
10060 // ---------------------------------------------------------------------------
10061 
10062 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
10063 {
10064  try
10065  {
10066  TrainController->LogEvent("PasteMenuItemClick");
10067  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
10068  // Level1Mode = TrackMode;
10069  // SetLevel1Mode(74);
10071  SetLevel2TrackMode(58);
10072  Utilities->CallLogPop(2060);
10073  }
10074  catch(const Exception &e)
10075  {
10076  ErrorLog(198, e.Message);
10077  }
10078 }
10079 
10080 // ---------------------------------------------------------------------------
10081 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
10082 {
10083  try
10084  {
10085  TrainController->LogEvent("DeleteMenuItemClick");
10086  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
10087  // Level1Mode = TrackMode;
10088  // SetLevel1Mode(75);
10090  SetLevel2TrackMode(38);
10091  Utilities->CallLogPop(1193);
10092  }
10093  catch(const Exception &e)
10094  {
10095  ErrorLog(153, e.Message);
10096  }
10097 }
10098 // ---------------------------------------------------------------------------
10099 
10100 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
10101 {
10102  try
10103  {
10104  TrainController->LogEvent("SelectLengthsMenuItemClick");
10105  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
10106  TrackElementPanel->Visible = false;
10107  TrackLengthPanel->Visible = true;
10108  TrackLengthPanel->SetFocus();
10109  SelectLengthsFlag = true;
10110  InfoPanel->Visible = true;
10111  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
10113  {
10114  ShowMessage("Note: length value will apply to each element's track within the selection.\n\nThis message will not be shown again.");
10115  LengthWarningSentFlag = true;
10116  }
10117  DistanceBox->Text = "";
10118  SpeedLimitBox->Text = "";
10121 // ResetChangedFileDataAndCaption(, true); //don't need this here after 2.7.0 as included in TrackLengthPanel buttons
10122  Utilities->CallLogPop(1414);
10123  }
10124  catch(const Exception &e)
10125  {
10126  ErrorLog(154, e.Message);
10127  }
10128 }
10129 
10130 // ---------------------------------------------------------------------------
10131 
10132 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
10133 {
10134 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
10135  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
10136 */
10137  try
10138  {
10139  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
10140  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
10142  bool FoundFlag = false;
10143  if(Track->SelectVector.empty())
10144  {
10145  Utilities->CallLogPop(1550);
10146  return;
10147  }
10148  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10149  {
10150  TTrackElement TE = Track->SelectVectorAt(14, x);
10151  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
10152  if(FoundFlag)
10153  {
10154  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
10155  {
10156  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10158  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10160  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
10162  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
10164  }
10165  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
10166  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
10167  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
10168  // at the same position
10169  {
10170  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10172  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10174  }
10175  }
10176  }
10178  ResetChangedFileDataAndCaption(22, false);
10179  // RlyFile = false; - don't alter this just for PrefDir changes
10180  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
10181  SetLevel1Mode(30);
10183  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
10184  Utilities->CallLogPop(1549);
10185  }
10186  catch(const Exception &e)
10187  {
10188  ErrorLog(155, e.Message);
10189  }
10190 }
10191 
10192 // ---------------------------------------------------------------------------
10193 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
10194 {
10195  try
10196  {
10197  TrainController->LogEvent("CancelSelectionClick");
10198  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
10199 // ClearandRebuildRailway(46); //called below
10200  SelectionValid = false;
10201  CancelSelectionFlag = true; // used to avoid RecoverClipboard in pasting when CutMoving selected
10202  Track->CopyFlag = false;
10204  if(Level1Mode == TrackMode)
10205  {
10206  SetLevel1Mode(76); // CancelSelectionFlag needed here
10208  SetLevel2TrackMode(68);
10209  }
10210  else if(Level1Mode == PrefDirMode)
10211  {
10212  SetLevel1Mode(32);
10213  }
10214  CancelSelectionFlag = false; // done with it
10215  ResetSelectRect();
10216  ClearandRebuildRailway(82); // to remove the selection outline
10217  Clipboard()->Clear();
10218  Clipboard()->Close();
10219  Utilities->CallLogPop(1413);
10220  }
10221  catch(const EClipboardException &e) // take no action
10222  {
10223 // Application->MessageBox(L"A clipboard error occurred in the cancel function", L"Message", MB_OK);
10224  }
10225  catch(const Exception &e)
10226  {
10227  ErrorLog(156, e.Message);
10228  }
10229 }
10230 
10231 // ---------------------------------------------------------------------------
10232 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
10233 {
10234  try
10235  {
10236  TrainController->LogEvent("LoadTimetableMenuItemClick");
10237  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
10238  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
10239  // reset all message flags, stops them being given twice new at v2.4.0
10240  TrainController->SSHigh = false;
10241  TrainController->MRSHigh = false;
10242  TrainController->MRSLow = false;
10243  TrainController->MassHigh = false;
10244  TrainController->BFHigh = false;
10245  TrainController->BFLow = false;
10246  TrainController->PwrHigh = false;
10247  TrainController->SigSHigh = false;
10248  TrainController->SigSLow = false;
10249  if(TimetableDialog->Execute())
10250  {
10251  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
10252  {
10253  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
10254  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
10255  }
10256  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
10257  bool CheckLocationsExistInRailwayTrue = true;
10258  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
10259  // true for GiveMessages
10260  {
10261  Screen->Cursor = TCursor(-11); // Hourglass;
10262  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
10263  if(TTBLFile.is_open())
10264  {
10265  bool SessionFileFalse = false;
10266  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
10267  {
10268  SaveTempTimetableFile(0, TimetableDialog->FileName);
10269  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
10270 
10271  }
10272  else
10273  {
10274  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
10275  }
10276  Screen->Cursor = TCursor(-2); // Arrow
10277  } // if(TimetableIntegrityCheck
10278  else
10279  {
10280  ShowMessage("Timetable preliminary integrity check failed - unable to load");
10281  }
10282  } // if(TimetableDialog->Execute())
10283 
10284  // else ShowMessage("Load Aborted");
10285  Utilities->CallLogPop(752);
10286  }
10287  catch(const Exception &e)
10288  {
10289  ErrorLog(34, e.Message);
10290  }
10291 }
10292 
10293 // ---------------------------------------------------------------------------
10294 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
10295 {
10296  try
10297  {
10298  TrainController->LogEvent("SignallerControl1Click");
10299  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
10301  Train.SignallerStoppingFlag = false;
10302  Train.TrainMode = Signaller;
10303  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
10304  {
10305  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
10306  }
10307  if(Train.Stopped())
10308  {
10309  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
10310  }
10311  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
10313  Train.PlotTrain(5, Display);
10314  AnsiString LocName = "";
10315  if(Train.LeadElement > -1)
10316  {
10317  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
10318  }
10319  if((LocName == "") && (Train.MidElement > -1))
10320  {
10321  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
10322  }
10323  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
10324  if(Train.StoppedAtLocation && (LocName != ""))
10325  {
10326  Train.RestoreTimetableLocation = LocName;
10327  }
10328  else
10329  {
10330  Train.RestoreTimetableLocation = "";
10331  }
10332  // check whether need to offer 'pass red signal'
10333  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
10334  {
10335  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
10336  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
10337  if((NextElementPosition > -1) && (NextEntryPos > -1))
10338  {
10339  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
10340  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
10341  {
10342  // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
10343  // forwards, but don't change the background colour so still shows as stopped at location
10344  Train.StoppedAtSignal = true;
10345  }
10346  }
10347  }
10348  // find element ID if no locname
10349  if((LocName == "") && Train.LeadElement > -1)
10350  {
10351  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
10352  }
10353  if((LocName == "") && (Train.MidElement > -1))
10354  {
10355  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
10356  }
10357  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10358  Utilities->CallLogPop(1772);
10359  }
10360  catch(const Exception &e)
10361  {
10362  ErrorLog(157, e.Message);
10363  }
10364 }
10365 
10366 // ---------------------------------------------------------------------------
10367 
10368 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
10369 {
10370  try
10371  {
10372  TrainController->LogEvent("TimetableControlMenuItemClick");
10373  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
10375  Train.SignallerStoppingFlag = false;
10376  Train.TrainMode = Timetable;
10377  Train.SignallerStopped = false;
10378  Train.StoppedAfterSPAD = false;
10379  Train.SPADFlag = false;
10382 // red headcode[0]
10383  Train.PlotTrain(6, Display);
10384  AnsiString LocName = "";
10385  if(Train.LeadElement > -1)
10386  {
10387  LocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
10388  }
10389  if((LocName == "") && (Train.MidElement > -1))
10390  {
10391  LocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
10392  }
10393  if((LocName == "") && Train.LeadElement > -1)
10394  {
10395  LocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
10396  }
10397  if((LocName == "") && (Train.MidElement > -1))
10398  {
10399  LocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
10400  }
10401  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
10402  {
10403  Train.StoppedAtLocation = true;
10404  Train.StoppedAtSignal = false;
10405 // added at v2.7.0 as if had been stopped at signal before tt control restored then background colour would change to normal when signal cleared even when not due to depart
10406  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
10407  // depart the departure time & TRS time have already been calculated so need to
10408  // force a recalculation - see below
10409  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
10410  if(!Train.TrainFailed)
10411  {
10413  }
10414  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10415  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
10416  {
10417  // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
10418  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
10419  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
10420  }
10421  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
10422  {
10423  // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
10424  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
10425  Train.TimeTimeLocArrived = true;
10426  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
10427  }
10428  }
10429  else
10430  {
10431  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas' error
10432  int NextEntryPos = -1; // ---ditto---
10433  if(Train.LeadElement > -1) // ---ditto---
10434  {
10435  // ---ditto---
10436  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10437  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10438  } // ---ditto---
10439 
10440  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10441  if(!Train.TrainFailed)
10442  {
10443  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
10444  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
10445 
10446  if(Train.AbleToMove(1)) // if has no power
10447  {
10448  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
10449  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
10450  Train.FirstHalfMove = true; // ---Ditto---
10451  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
10452  {
10453  // Train.EntrySpeed = 0;
10454  // Train.EntryTime = TrainController->TTClockTime;
10455  // Train.FirstHalfMove = true;
10456  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
10457  }
10458  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
10459  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
10460  {
10461  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
10462  }
10463  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
10464  {
10465  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
10466  }
10467  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
10468  {
10469  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
10470  }
10471  }
10472  else if(Train.StoppedAtSignal)
10473  {
10474  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10475  if(!Train.TrainFailed)
10476  {
10478  }
10479  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
10480  }
10481  }
10482  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10483  Utilities->CallLogPop(1195);
10484  }
10485  catch(const Exception &e)
10486  {
10487  ErrorLog(158, e.Message);
10488  }
10489 }
10490 
10491 // ---------------------------------------------------------------------------
10492 
10493 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
10494 {
10495  try
10496  {
10497  TrainController->LogEvent("ChangeDirectionMenuItemClick");
10498  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
10500  Train.SignallerStoppingFlag = false;
10501  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
10502  Train.SignallerStopped = true;
10503  AnsiString LocName = "";
10504  if(Train.LeadElement > -1)
10505  {
10506  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
10507  }
10508  if((LocName == "") && (Train.MidElement > -1))
10509  {
10510  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
10511  }
10512  if((LocName == "") && Train.LeadElement > -1)
10513  {
10514  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
10515  }
10516  if((LocName == "") && (Train.MidElement > -1))
10517  {
10518  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
10519  }
10520  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10521  Utilities->CallLogPop(1196);
10522  }
10523  catch(const Exception &e)
10524  {
10525  ErrorLog(159, e.Message);
10526  }
10527 }
10528 // ---------------------------------------------------------------------------
10529 
10530 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
10531 {
10532  try
10533  {
10534  TrainController->LogEvent("MoveForwardsMenuItemClick");
10535  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
10537  Train.SignallerStoppingFlag = false;
10538  if(!Train.AbleToMove(2))
10539  {
10540  // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
10541  Utilities->CallLogPop(1197);
10542  return;
10543  }
10544  Train.SignallerStopped = false;
10545  Train.StoppedAfterSPAD = false; // in case had been set
10546  Train.SPADFlag = false;
10547  Train.StoppedAtLocation = false; // may not have been set but reset anyway
10548  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10550  Train.EntrySpeed = 0;
10552  Train.FirstHalfMove = true;
10553  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
10554  int NextEntryPos = -1; // ---ditto---
10555  if(Train.LeadElement > -1) // ---ditto---
10556  {
10557  // ---ditto---
10558  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10559  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10560  } // ---ditto---
10561 
10562  if((NextElementPos > -1) && (NextEntryPos > -1))
10563  {
10564  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10565  }
10566  // else follow the continuations
10567  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
10568  {
10569  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
10570  }
10571  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
10572  {
10573  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
10574  }
10575  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
10576  {
10577  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
10578  }
10579  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10580  Utilities->CallLogPop(1198);
10581  }
10582  catch(const Exception &e)
10583  {
10584  ErrorLog(160, e.Message);
10585  }
10586 }
10587 // ---------------------------------------------------------------------------
10588 
10589 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
10590 {
10591  // new at v2.4.0
10592  try
10593  {
10594  TrainController->LogEvent("JoinedByMenuItemClick");
10595  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
10596  TTrain *TrainToBeJoinedBy;
10598  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
10599  {
10600  if(TrainToBeJoinedBy->TrainMode != Signaller)
10601  {
10602  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
10603  Utilities->CallLogPop(2156);
10604  return;
10605  }
10606  // here if there is an adjacent train under signaller control
10607  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
10608  {
10609  ShowMessage("Can't join two trains when both are without power");
10610  Utilities->CallLogPop(2157);
10611  return;
10612  }
10613  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
10614  // set new values for mass etc
10615  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
10616  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
10617  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
10618  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
10619  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
10620  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
10621  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
10622 
10623  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
10624  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
10625  AnsiString LocName = "";
10626  if(ThisTrain.LeadElement > -1)
10627  {
10628  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
10629  }
10630  if((LocName == "") && (ThisTrain.MidElement > -1))
10631  {
10632  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
10633  }
10634  if((LocName == "") && ThisTrain.LeadElement > -1)
10635  {
10636  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
10637  }
10638  if((LocName == "") && (ThisTrain.MidElement > -1))
10639  {
10640  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
10641  }
10642  ThisTrain.StoppedWithoutPower = true;
10643  if(ThisTrain.PowerAtRail >= 1)
10644  {
10645  ThisTrain.StoppedWithoutPower = false;
10646  }
10647  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
10648  if(!ThisTrain.StoppedAtLocation)
10649  {
10650  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10652  }
10653  else
10654  {
10655  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10657  }
10658  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
10659  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
10660  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
10661  ThisTrain.ZeroPowerNoRearSplitMessage = false;
10662  ThisTrain.FailedTrainNoFinishJoinMessage = false;
10663  ThisTrain.ZeroPowerNoJoinedByMessage = false;
10664  ThisTrain.ZeroPowerNoCDTMessage = false;
10665  ThisTrain.ZeroPowerNoNewServiceMessage = false;
10667  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
10669  Utilities->CallLogPop(2158);
10670  }
10671  }
10672  catch(const Exception &e)
10673  {
10674  ErrorLog(207, e.Message);
10675  }
10676 }
10677 // ---------------------------------------------------------------------------
10678 
10679 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
10680 {
10681  // added at v2.4.0
10682  try
10683  {
10684  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
10685  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
10687  Train.TrainFailed = false;
10688  Train.StoppedWithoutPower = false;
10689  Train.SignallerStopped = true;
10690  if(!Train.StoppedAtLocation)
10691  {
10692  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10694  }
10695  else
10696  {
10697  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10699  }
10700  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
10701  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
10702  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
10703  AnsiString LocName = "";
10704  if(Train.LeadElement > -1)
10705  {
10706  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
10707  }
10708  if((LocName == "") && (Train.MidElement > -1))
10709  {
10710  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
10711  }
10712  if((LocName == "") && Train.LeadElement > -1)
10713  {
10714  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
10715  }
10716  if((LocName == "") && (Train.MidElement > -1))
10717  {
10718  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
10719  }
10720  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
10721  Train.ZeroPowerNoFrontSplitMessage = false;
10722  Train.ZeroPowerNoRearSplitMessage = false;
10723  Train.FailedTrainNoFinishJoinMessage = false;
10724  Train.ZeroPowerNoJoinedByMessage = false;
10725  Train.ZeroPowerNoCDTMessage = false;
10726  Train.ZeroPowerNoNewServiceMessage = false;
10728  Train.ZeroPowerNoRepeatShuttleMessage = false;
10730  Utilities->CallLogPop(2159);
10731  }
10732  catch(const Exception &e)
10733  {
10734  ErrorLog(208, e.Message);
10735  }
10736 }
10737 
10738 // ---------------------------------------------------------------------------
10739 
10740 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
10741 {
10742  try
10743  {
10744  TrainController->LogEvent("SignallerControlStopMenuItemClick");
10745  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
10748  if(Train.LeadElement > -1)
10749  {
10750  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10751  {
10752  Train.SignallerStoppingFlag = true;
10753  Train.SignallerStopBrakeRate = 0;
10754  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10755  }
10756  else
10757  {
10759  }
10760  }
10761  else
10762  {
10764  }
10765  Utilities->CallLogPop(1553);
10766  }
10767  catch(const Exception &e)
10768  {
10769  ErrorLog(161, e.Message);
10770  }
10771 }
10772 
10773 // ---------------------------------------------------------------------------
10774 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
10775 {
10776  try
10777  {
10778  TrainController->LogEvent("PassRedSignalMenuItemClick");
10779  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
10781  Train.SignallerStoppingFlag = false;
10782  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
10783  if(NextElementPos < 0)
10784  {
10785  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
10786  }
10787  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
10788 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
10789  if(!Train.StoppedAtSignal)
10790  {
10791  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
10792  }
10793 */
10794  if(TrackElement.TrackType != SignalPost)
10795  {
10796  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
10797  }
10798  Train.SignallerStopped = false;
10799  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10800  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10801  // since no need to alert the user
10802  Train.StoppedAfterSPAD = false; // in case had been set
10803  Train.SPADFlag = false;
10804  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10806  Train.AllowedToPassRedSignal = true;
10807  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10808  Utilities->CallLogPop(1199);
10809  }
10810  catch(const Exception &e)
10811  {
10812  ErrorLog(162, e.Message);
10813  }
10814 }
10815 // ---------------------------------------------------------------------------
10816 
10817 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
10818 {
10819  try
10820  {
10821  TrainController->LogEvent("StepForwardMenuItemClick");
10822  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
10824  Train.SignallerStoppingFlag = false;
10825  Train.SignallerStopped = false;
10826  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10827  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10828  // since no need to alert the user
10829  Train.StoppedAfterSPAD = false; // in case had been set
10830  Train.SPADFlag = false;
10831  Train.StepForwardFlag = true;
10832  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
10833  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10835  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10836  int NextElementPos = -1;
10837 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
10838  int NextEntryPos = -1; // ---ditto---
10839  if(Train.LeadElement > -1) // ---ditto---
10840  {
10841  // ---ditto---
10842  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10843  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10844  } // ---ditto---
10845 
10846  if((NextElementPos > -1) && (NextEntryPos > -1))
10847  {
10848  // call this after StepForwardFlag set
10849  Train.EntrySpeed = 0;
10851  Train.FirstHalfMove = true;
10852  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10853  }
10854  Utilities->CallLogPop(1800);
10855  }
10856  catch(const Exception &e)
10857  {
10858  ErrorLog(163, e.Message);
10859  }
10860 }
10861 
10862 // ---------------------------------------------------------------------------
10863 
10864 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
10865 {
10866  try
10867  {
10868  TrainController->LogEvent("RemoveTrainMenuItemClick");
10869  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
10871  if((!Train.Derailed) && (!Train.Crashed))
10872  {
10873  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10875  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
10876  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
10877  TrainController->BaseTime = TDateTime::CurrentDateTime();
10879  if(button == IDNO)
10880  {
10881  Utilities->CallLogPop(1801);
10882  return;
10883  }
10884  }
10885  Train.SignallerStoppingFlag = false;
10886  Train.TrainGone = true; // will be removed by TTrainController::Operate
10887  Train.SignallerRemoved = true;
10888  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
10889  AnsiString LocName = "";
10890  if(Train.LeadElement > -1)
10891  {
10892  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
10893  }
10894  if((LocName == "") && (Train.MidElement > -1))
10895  {
10896  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
10897  }
10898  if((LocName == "") && Train.LeadElement > -1)
10899  {
10900  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
10901  }
10902  if((LocName == "") && (Train.MidElement > -1))
10903  {
10904  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
10905  }
10906  TTrackElement *TrackElementPtr;
10907  int RouteNumber;
10908  TAllRoutes::TRouteType RouteType;
10909  if(Train.LeadElement > -1)
10910  {
10911  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
10912  // remove TrainIDs from track element, added at v2.4.0
10913  if(TrackElementPtr->TrackType == Bridge)
10914  {
10915  if(Train.LeadExitPos > 1)
10916  {
10917  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10918  }
10919  else
10920  {
10921  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10922  }
10923  }
10924  else
10925  {
10926  TrackElementPtr->TrainIDOnElement = -1;
10927  }
10928  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
10929  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10930  {
10931  TrackElementPtr->CallingOnSet = false;
10932  Track->PlotSignal(6, *TrackElementPtr, Display);
10933  }
10934 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
10935 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
10936  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
10937  if(RouteType == TAllRoutes::AutoSigsRoute)
10938  {
10941  }
10942 // end of addition
10943 
10944 // erase a stub route if there is one, added at v2.6.1
10945 // first element of route is immediately in front of the train
10946  if(Train.LeadExitPos >= 0)
10947  {
10948  TTrackElement LeadTrackElement = Track->TrackElementAt(1013, Train.LeadElement);
10949  int FirstRouteElementVecPos = LeadTrackElement.Conn[Train.LeadExitPos];
10950  int FirstRouteLinkPos = LeadTrackElement.ConnLinkPos[Train.LeadExitPos];
10951  RouteType = AllRoutes->GetRouteTypeAndNumber(39, FirstRouteElementVecPos, FirstRouteLinkPos, RouteNumber);
10952  if(RouteType == TAllRoutes::NotAutoSigsRoute) // red or green route, if no route then ignore
10953  {
10954  TOneRoute &OR = AllRoutes->GetModifiableRouteAt(30, RouteNumber);
10955  TTrackElement TE = Track->TrackElementAt(1014, FirstRouteElementVecPos);
10956  if((TE.TrackType != SignalPost) && (TE.TrackType != Continuation))
10957  // all autosigs routes have signalpost or continuation at 0 so they are automatically excluded
10958  {
10959  bool FirstPass = true; //added at v2.8.0
10960  while(OR.PrefDirSize() > 0)
10961  // remove the route up to but not including the next facing signal, in case a route extends to another signal
10962  {
10963  TPrefDirElement PDE = OR.GetFixedPrefDirElementAt(249, 0);
10964 // these will change at each element removal because OR is a reference to the real route
10965  int TVPos2 = PDE.GetTrackVectorPosition();
10966  if(FirstPass && (TVPos2 != FirstRouteElementVecPos)) //route is not directed away from cdt train, could be a call-on for another train (added at v2.8.0)
10967  {
10968  break;
10969  }
10970  TTrackElement TE2 = Track->TrackElementAt(1015, TVPos2);
10971  if(Track->TrackElementAt(1016, PDE.GetTrackVectorPosition()).Config[PDE.GetXLinkPos()] != Signal)
10972  {
10973  AllRoutes->RemoveRouteElement(24, TE2.HLoc, TE2.VLoc, PDE.GetELink());
10974  }
10975  else
10976  {
10977  break;
10978  }
10979  FirstPass = false;
10980  }
10981  AllRoutes->RebuildRailwayFlag = true;
10982  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to replot without stub route
10983  }
10984  }
10985  }
10986 // end of stub route removal addition
10987  }
10988  if(Train.MidElement > -1)
10989  {
10990  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
10991  // remove TrainIDs from track element, added at v2.4.0
10992  if(TrackElementPtr->TrackType == Bridge)
10993  {
10994  if(Train.MidExitPos > 1)
10995  {
10996  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10997  }
10998  else
10999  {
11000  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
11001  }
11002  }
11003  else
11004  {
11005  TrackElementPtr->TrainIDOnElement = -1;
11006  }
11007  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
11008  {
11009  TrackElementPtr->CallingOnSet = false;
11010  Track->PlotSignal(7, *TrackElementPtr, Display);
11011  }
11012 // [added at v1.3.0 as above]
11014  {
11015  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
11016  if(RouteType == TAllRoutes::AutoSigsRoute)
11017  {
11020  }
11021  }
11022 // end of addition
11023  }
11024  if(Train.LeadElement > -1)
11025  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
11026  {
11027  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
11028  {
11029  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
11030  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
11031  {
11032  TrackElementPtr->CallingOnSet = false;
11033  Track->PlotSignal(8, *TrackElementPtr, Display);
11034  }
11035  }
11036  }
11037  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11038  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
11039  {
11040  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
11041  } // entries, including Fer if present
11042 
11043  Utilities->CallLogPop(1200);
11044  }
11045  catch(const Exception &e)
11046  {
11047  ErrorLog(164, e.Message);
11048  }
11049 }
11050 
11051 // ---------------------------------------------------------------------------
11052 
11053 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
11054 // to terminate after error message given
11055 {
11056  ErrorMessage->Visible = false;
11057  ErrorMessageStoreImage->Visible = false;
11058  ErrorButton->Visible = false;
11059  Display->GetImage()->Visible = true;
11060  Application->Terminate();
11061 }
11062 
11063 // ---------------------------------------------------------------------------
11064 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
11065 {
11066  try
11067  {
11068  TrainController->LogEvent("PerformancePanelLabelStartDrag");
11069  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
11070  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
11071  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
11072  Utilities->CallLogPop(1202);
11073  }
11074  catch(const Exception &e)
11075  {
11076  ErrorLog(165, e.Message);
11077  }
11078 }
11079 // ---------------------------------------------------------------------------
11080 
11081 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
11082 {
11083  try
11084  {
11085  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
11087  {
11088  UnicodeString MessageStr =
11089  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
11090  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
11091  if(button == IDNO)
11092  {
11093  Action = caNone; // prevents form & application from closing
11094  Utilities->CallLogPop(1712);
11095  return;
11096  }
11097  }
11099  {
11100  UnicodeString MessStr = "";
11102  {
11103  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
11104  }
11105  else if(FileChangedFlag)
11106  {
11107  MessStr = UnicodeString("The railway has changed, exit without saving?");
11108  }
11109  else
11110  {
11111  MessStr = UnicodeString("The timetable has changed, exit without saving?");
11112  }
11113  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
11114  if(button == IDNO)
11115  {
11116  Action = caNone; // prevents form & application from closing
11117  Utilities->CallLogPop(1133);
11118  return;
11119  }
11120  }
11121  if(Level1Mode == OperMode)
11122  {
11124  {
11125  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
11126  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
11128  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
11129  TrainController->BaseTime = TDateTime::CurrentDateTime();
11131  if(button == IDNO)
11132  {
11133  Action = caNone; // prevents form & application from closing
11134  Utilities->CallLogPop(969);
11135  return;
11136  }
11137  }
11139  Utilities->PerformanceFile.close();
11140  }
11141  if((TempTTFileName != "") && FileExists(TempTTFileName))
11142  {
11143  DeleteFile(TempTTFileName);
11144  }
11145  Utilities->CallLogPop(971);
11146  }
11147  catch(const Exception &e)
11148  {
11149  ErrorLog(166, e.Message);
11150  }
11151 }
11152 
11153 // ---------------------------------------------------------------------------
11154 
11155 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
11156 {
11157 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
11158 // drop event log as have too many spurious entries
11159  try
11160  {
11161  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
11162  {
11163  if(Key == '2')
11164  {
11165  if(CallLogTickerLabel->Visible)
11166  {
11167  CallLogTickerLabel->Visible = false;
11168  }
11169  else
11170  {
11171  CallLogTickerLabel->Visible = true;
11172  }
11173  }
11174  else if(Key == '3')
11175  {
11176  if(DevelopmentPanel->Visible)
11177  {
11178  DevelopmentPanel->Visible = false;
11179  }
11180  else
11181  {
11182  DevelopmentPanel->Visible = true;
11183  DevelopmentPanel->BringToFront();
11184  }
11185  }
11186  else if(Key == '4')
11187  {
11188  TestFunction();
11189  }
11190  else if(Key == '5')
11191  {
11192  TMsgDlgButtons Buttons;
11193  Buttons << mbYes << mbNo;
11194  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.",
11195  mtWarning, Buttons, 0) == mrYes)
11196  {
11198  }
11199  else
11200  {
11202  }
11203  }
11204  }
11205  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
11206  {
11207  CtrlKey = true;
11208  }
11209  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
11210  {
11211  ShiftKey = true;
11212  }
11213 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
11214 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
11215 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
11216 
11217 // at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
11218 // is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
11219 // won't work on first press and that is less likely to be used a second time on either side of the message
11220 
11221  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
11222  {
11223  if(LastNonCtrlOrShiftKeyDown == Key) // same key still down rejected
11224  {
11225  return;
11226  }
11227  else
11228  {
11230  }
11231  }
11232  if(Key == VK_UP)
11233  {
11234  if(ScreenUpButton->Enabled)
11235  {
11236  ScreenUpButton->Click();
11237  }
11238  }
11239  else if(Key == VK_DOWN)
11240  {
11241  if(ScreenDownButton->Enabled)
11242  {
11243  ScreenDownButton->Click();
11244  }
11245  }
11246  else if(Key == VK_LEFT)
11247  {
11248  if(ScreenLeftButton->Enabled)
11249  {
11250  ScreenLeftButton->Click();
11251  }
11252  }
11253  else if(Key == VK_RIGHT)
11254  {
11255  if(ScreenRightButton->Enabled)
11256  {
11257  ScreenRightButton->Click();
11258  }
11259  }
11260  else if(Key == VK_HOME)
11261  {
11262  if(HomeButton->Enabled)
11263  {
11264  HomeButton->Click();
11265  }
11266  }
11267 // end of 1.3.0 addition
11268  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
11269  {
11270  if(ZoomButton->Enabled)
11271  {
11272  ZoomButton->Click();
11273  }
11274  }
11275  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
11276  {
11277  if(ZoomButton->Enabled)
11278  {
11279  ZoomButton->Click();
11280  }
11281  }
11282 // below added for v2.4.2 to add more keyboard shortcuts
11283  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
11284  SpeedEditBox2->Focused() || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() ||
11285  SpeedEditBox->Focused() || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
11286  {
11287  // prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
11288  return;
11289  }
11290  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
11291  {
11292  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h')) // TimetablePanel uses Shift H too so disable this when it's in use
11293  {
11294  NewHomeButton->Click();
11295  }
11296  }
11297 // Operating panel
11298  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
11299  {
11300  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
11301  if(!Shift.Contains(ssCtrl))
11302  {
11303  if(OperateButton->Visible && OperateButton->Enabled)
11304  {
11305  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
11306  {
11307  OperateButton->Click();
11308  }
11309  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
11310  {
11311  OperateButton->Click();
11312  }
11313  }
11314  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
11315  {
11316  PresetAutoSigRoutesButton->Click();
11317  }
11318  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
11319  {
11320  PerformanceLogButton->Click();
11321  }
11322  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
11323  {
11324  CallingOnButton->Click();
11325  }
11326  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
11327  {
11328  OperatorActionButton->Click();
11329  }
11330  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
11331  {
11332  RouteCancelButton->Click();
11333  }
11334  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
11335  {
11336  TTClockAdjButton->Click();
11337  }
11338  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') // route buttons - autosigs
11339  {
11340  AutoSigsButton->Click();
11341  }
11342  if(SigPrefConsecButton->Visible && SigPrefConsecButton->Enabled && Key == '2') // route buttons - prefdir
11343  {
11344  SigPrefConsecButton->Click();
11345  }
11346  if(SigPrefNonConsecButton->Visible && SigPrefNonConsecButton->Enabled && Key == '4') // added at v2.7.0 for prefdir & any following signal
11347  {
11348  SigPrefNonConsecButton->Click();
11349  }
11350  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') // route buttons - unrestricted
11351  {
11352  UnrestrictedButton->Click();
11353  }
11354  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
11355  {
11356  ExitOperationButton->Click();
11357  }
11358  }
11359  else // CtrlKey down
11360  {
11361  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
11362  {
11363  SaveMenuItem->ShortCut = 0;
11364 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
11365  if(Key == 'S' || Key == 's') // so this will never execute
11366  {
11367  SaveSessionButton->Click();
11368  }
11369  }
11370  }
11371  }
11372 // Timetable clock adjust panel
11373  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
11374  {
11375  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
11376  if(Shift.Contains(ssShift))
11377  {
11378  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
11379  {
11380  TTClockExitButton->Click();
11381  }
11382  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
11383  {
11384  TTClockResetButton->Click();
11385  }
11386  }
11387  }
11388 // Track build panel
11389  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
11390  {
11391  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
11392  {
11393  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) // add/remove track elements
11394  {
11395  AddTrackButton->Click();
11396  }
11397  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) // cycle through signal aspects
11398  {
11399  SigAspectButton->Click();
11400  }
11401  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) // link track
11402  {
11403  TrackOKButton->Click();
11404  }
11405  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) // change font
11406  {
11407  FontButton->Click();
11408  }
11409  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) // name locations
11410  {
11411  LocationNameButton->Click();
11412  }
11413  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) // set distances/speeds
11414  {
11415  SetLengthsButton->Click();
11416  }
11417  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) // add text
11418  {
11419  AddTextButton->Click();
11420  }
11421  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) // toggle grid
11422  {
11423  ScreenGridButton->Click();
11424  }
11425  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) // move text or graphic
11426  {
11427  MoveTextOrGraphicButton->Click();
11428  }
11429  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) // insert image
11430  {
11431  UserGraphicButton->Click();
11432  }
11433  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) // join gaps
11434  {
11435  SetGapsButton->Click();
11436  }
11437  }
11438  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
11439  {
11440  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) // save railway in trackbuild mode
11441  {
11442  SaveMenuItem->ShortCut = 0;
11443 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
11444  if(Key == 'S' || Key == 's') // so this will never execute
11445  {
11446  SaveRailwayTBPButton->Click();
11447  }
11448  }
11449  }
11450  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
11451  {
11452  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') // escape key
11453  {
11454  ExitTrackButton->Click();
11455  }
11456  }
11457  }
11458 // PrefDir panel
11459  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
11460  {
11461  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11462  {
11463  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') // escape key
11464  {
11465  ExitPrefDirButton->Click();
11466  }
11467  }
11468  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
11469  {
11470  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
11471  {
11472  SaveMenuItem->ShortCut = 0;
11473 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
11474  if(Key == 'S' || Key == 's') // so this will never execute
11475  {
11476  SaveRailwayPDPButton->Click();
11477  }
11478  }
11479  }
11480  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11481  {
11482  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) // add pref dir
11483  {
11484  AddPrefDirButton->Click();
11485  }
11486  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) // delete one pref dir
11487  {
11488  DeleteOnePrefDirButton->Click();
11489  }
11490  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) // delete all pref dirs
11491  {
11492  DeleteAllPrefDirButton->Click();
11493  }
11494  }
11495  }
11496 // Note that save button in BaseMode is handled by Ctrl S from the File menu
11497 
11498 // Timetable panel
11499  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
11500  {
11501  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11502  {
11503  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') // escape key
11504  {
11505  ExitTTModeButton->Click();
11506  }
11507  }
11508  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) // show/hide timetable edit panel
11509  {
11510  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
11511  {
11512  if(!TimetableEditPanel->Visible)
11513  {
11514  if(Key == 'S' || Key == 's')
11515  {
11516  ShowHideTTButton->Click();
11517  }
11518  }
11519  else if(Key == 'H' || Key == 'h')
11520  {
11521  ShowHideTTButton->Click();
11522  }
11523  }
11524  }
11525  }
11526 // Timetable edit panel
11527 // These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
11528 // is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
11529 // showing. See DevHistory.txt for the version after v2.4.3 for details.
11530  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
11531  {
11532  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11533  {
11535 // store value here before the Windows key press function runs (it runs after any local code)
11536  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
11537  {
11538  PreviousTTEntryKeyFlag = true;
11539  }
11540  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
11541  {
11542  NextTTEntryKeyFlag = true;
11543  }
11544  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
11545  {
11546  MoveTTEntryUpKeyFlag = true;
11547  }
11548  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
11549  {
11550  MoveTTEntryDownKeyFlag = true;
11551  }
11552  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
11553  {
11554  CopyTTEntryKeyFlag = true;
11555  }
11556  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
11557  {
11558  CutTTEntryKeyFlag = true;
11559  }
11560  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
11561  {
11562  PasteTTEntryKeyFlag = true;
11563  }
11564  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
11565  {
11566  DeleteTTEntryKeyFlag = true;
11567  }
11568 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
11569  {
11570  SaveTTEntryKeyFlag = true;
11571  }
11572  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
11573  {
11574  CancelTTActionKeyFlag = true;
11575  }
11576 */
11577  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
11578  {
11579  NewTTEntryKeyFlag = true;
11580  }
11581  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
11582  {
11583  AZOrderKeyFlag = true;
11584  }
11585 /*
11586  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
11587  {
11588  AddMinsKeyFlag = true;
11589  }
11590  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
11591  {
11592  SubMinsKeyFlag = true;
11593  }
11594 */
11595  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
11596  {
11598  }
11599  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
11600  {
11601  ValidateTimetableKeyFlag = true;
11602  }
11603  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
11604  {
11605  SaveTTKeyFlag = true;
11606  }
11607  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
11608  {
11609  SaveTTAsKeyFlag = true;
11610  }
11611  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
11612  {
11613  RestoreTTKeyFlag = true;
11614  }
11615  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
11616  {
11617  ExportTTKeyFlag = true;
11618  }
11619  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
11620  {
11621  ConflictAnalysisKeyFlag = true;
11622  }
11623  }
11624  }
11625 // Information menu
11626  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
11627  {
11628  if(Key == 'I' || Key == 'i') // toggle track info
11629  {
11630  TrackInfoOnOffMenuItem->Click();
11631  }
11632  else if(TrainInfoMenuItem->Enabled)
11633  {
11634  if(Key == 'S' || Key == 's') // toggle train status info
11635  {
11637  }
11638  else if(Key == 'T' || Key == 't') // toggle train timetable info
11639  {
11640  TrainTTInfoOnOffMenuItem->Click();
11641  }
11642  }
11643  }
11644 // end of 2.4.2 addition
11645 
11646  }
11647  catch(const Exception &e)
11648  {
11649  ErrorLog(167, e.Message);
11650  }
11651 }
11652 
11653 // ---------------------------------------------------------------------------
11654 
11655 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11656 {
11657  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
11658  {
11659  LastNonCtrlOrShiftKeyDown = -1; // reset value to no key down
11660  }
11661  CtrlKey = false;
11662  ShiftKey = false;
11663  SaveMenuItem->ShortCut = 16467; // restore Ctrl S for save menu in case set to 0 in FormKeyDown
11664 }
11665 
11666 // ---------------------------------------------------------------------------
11667 
11668 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11669 {
11670  if((Button == mbRight) && Level2OperMode == Operating)
11671  {
11672  OutputLog1->Caption = "";
11673  }
11674 }
11675 
11676 // ---------------------------------------------------------------------------
11677 
11678 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11679 {
11680  if((Button == mbRight) && Level2OperMode == Operating)
11681  {
11682  OutputLog2->Caption = "";
11683  }
11684 }
11685 // ---------------------------------------------------------------------------
11686 
11687 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11688 {
11689  if((Button == mbRight) && Level2OperMode == Operating)
11690  {
11691  OutputLog3->Caption = "";
11692  }
11693 }
11694 
11695 // ---------------------------------------------------------------------------
11696 
11697 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11698 {
11699  if((Button == mbRight) && Level2OperMode == Operating)
11700  {
11701  OutputLog4->Caption = "";
11702  }
11703 }
11704 
11705 // ---------------------------------------------------------------------------
11706 
11707 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11708 {
11709  if((Button == mbRight) && Level2OperMode == Operating)
11710  {
11711  OutputLog5->Caption = "";
11712  }
11713 }
11714 // ---------------------------------------------------------------------------
11715 
11716 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11717 {
11718  if((Button == mbRight) && Level2OperMode == Operating)
11719  {
11720  OutputLog6->Caption = "";
11721  }
11722 }
11723 
11724 // ---------------------------------------------------------------------------
11725 
11726 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11727 {
11728  if((Button == mbRight) && Level2OperMode == Operating)
11729  {
11730  OutputLog7->Caption = "";
11731  }
11732 }
11733 
11734 // ---------------------------------------------------------------------------
11735 
11736 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11737 {
11738  if((Button == mbRight) && Level2OperMode == Operating)
11739  {
11740  OutputLog8->Caption = "";
11741  }
11742 }
11743 
11744 // ---------------------------------------------------------------------------
11745 
11746 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11747 {
11748  if((Button == mbRight) && Level2OperMode == Operating)
11749  {
11750  OutputLog9->Caption = "";
11751  }
11752 }
11753 
11754 // ---------------------------------------------------------------------------
11755 
11756 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11757 {
11758  if((Button == mbRight) && Level2OperMode == Operating)
11759  {
11760  OutputLog10->Caption = "";
11761  }
11762 }
11763 
11764 // ---------------------------------------------------------------------------
11765 
11766 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
11767 {
11768  try
11769  {
11770  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
11771  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
11772  {
11774  SetLevel2OperMode(3);
11775  MasterClock->Enabled = false;
11776  }
11777  AboutForm->ShowModal();
11778  }
11779  catch(const Exception &e)
11780  {
11781  ErrorLog(168, e.Message);
11782  }
11783 }
11784 
11785 // ---------------------------------------------------------------------------
11786 
11787 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
11788 {
11789  try
11790  {
11791  // Helpfile allocated during construction of Interface
11792  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
11793  }
11794  catch(const Exception &e)
11795  {
11796  ErrorLog(175, e.Message);
11797  }
11798 }
11799 
11800 // ---------------------------------------------------------------------------
11801 
11802 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
11803 {
11804  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
11805  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
11806 }
11807 
11808 // ---------------------------------------------------------------------------
11809 
11810 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
11811 {
11812  try
11813  {
11814  TrainController->LogEvent("BlackBgndMenuItemClick");
11815  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
11816  TColor OldTransparentColour = Utilities->clTransparent;
11817  Utilities->clTransparent = TColor(0);
11818  SelectBitmap->TransparentColor = Utilities->clTransparent;
11821 
11822  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11823  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11824  Level1Mode = BaseMode;
11825  SetLevel1Mode(128);
11826  Utilities->CallLogPop(1797);
11827  }
11828  catch(const Exception &e)
11829  {
11830  ErrorLog(170, e.Message);
11831  }
11832 }
11833 
11834 // ---------------------------------------------------------------------------
11835 
11836 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
11837 {
11838  try
11839  {
11840  TrainController->LogEvent("WhiteBgndMenuItemClick");
11841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
11842  TColor OldTransparentColour = Utilities->clTransparent;
11843  Utilities->clTransparent = TColor(0xFFFFFF);
11844  SelectBitmap->TransparentColor = Utilities->clTransparent;
11847 
11848  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11849  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11850  Level1Mode = BaseMode;
11851  SetLevel1Mode(129);
11852  Utilities->CallLogPop(1798);
11853  }
11854  catch(const Exception &e)
11855  {
11856  ErrorLog(171, e.Message);
11857  }
11858 }
11859 
11860 // ---------------------------------------------------------------------------
11861 
11862 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
11863 {
11864  try
11865  {
11866  TrainController->LogEvent("BlueBgndMenuItemClick");
11867  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
11868  TColor OldTransparentColour = Utilities->clTransparent;
11869  Utilities->clTransparent = TColor(0x330000);
11870  SelectBitmap->TransparentColor = Utilities->clTransparent;
11873 
11874  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11875  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11876  Level1Mode = BaseMode;
11877  SetLevel1Mode(130);
11878  Utilities->CallLogPop(1799);
11879  }
11880  catch(const Exception &e)
11881  {
11882  ErrorLog(172, e.Message);
11883  }
11884 }
11885 
11886 // ---------------------------------------------------------------------------
11887 
11888 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
11889 {
11890  if(SpeedTopLabel->Caption == "mph")
11891  {
11892  SpeedTopLabel->Caption = "km/h";
11893  SpeedBottomLabel->Caption = "mph";
11894  }
11895  else
11896  {
11897  SpeedTopLabel->Caption = "mph";
11898  SpeedBottomLabel->Caption = "km/h";
11899  }
11900  // swap values to match toggle state
11901  UnicodeString SavedTopValue = SpeedEditBox->Text;
11902  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
11903 
11904  SpeedEditBox->Text = SavedBottomValue;
11905  SpeedVariableLabel->Caption = SavedTopValue;
11906 }
11907 // ---------------------------------------------------------------------------
11908 
11909 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
11910 {
11911  if(SpeedTopLabel2->Caption == "mph")
11912  {
11913  SpeedTopLabel2->Caption = "km/h";
11914  SpeedBottomLabel2->Caption = "mph";
11915  }
11916  else
11917  {
11918  SpeedTopLabel2->Caption = "mph";
11919  SpeedBottomLabel2->Caption = "km/h";
11920  }
11921  // swap values to match toggle state
11922  UnicodeString SavedTopValue = SpeedEditBox2->Text;
11923  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
11924 
11925  SpeedEditBox2->Text = SavedBottomValue;
11926  SpeedVariableLabel2->Caption = SavedTopValue;
11927 }
11928 // ---------------------------------------------------------------------------
11929 
11930 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11931 {
11932  try
11933  {
11934  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
11935  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
11936  bool ErrorFlag = false, TooBigFlag = false;
11937  if(SpeedEditBox->Text.Length() > 0)
11938  {
11939  if(SpeedEditBox->Text.Length() > 5)
11940  {
11941  TooBigFlag = true;
11942  }
11943  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
11944  {
11945  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
11946  {
11947  SpeedVariableLabel->Caption = "Entry error";
11948  ErrorFlag = true;
11949  break;
11950  }
11951  if(TooBigFlag)
11952  {
11953  SpeedVariableLabel->Caption = "Too big";
11954  break;
11955  }
11956  }
11957  if(!ErrorFlag && !TooBigFlag)
11958  {
11959 /*
11960  1 mph = 1.609344 km/h
11961  1 km/h = 0.621371 mph
11962 */
11963  if(SpeedTopLabel->Caption == "mph")
11964  {
11965  // do mph-to-km/h conversion
11966  int MPH = SpeedEditBox->Text.ToInt();
11967  int KPH = (MPH * 1.609344) + 0.5;
11968  SpeedVariableLabel->Caption = UnicodeString(KPH);
11969  }
11970  else
11971  {
11972  // do km/h-to-mph conversion
11973  int KPH = SpeedEditBox->Text.ToInt();
11974  int MPH = (KPH * 0.621371) + 0.5;
11975  SpeedVariableLabel->Caption = UnicodeString(MPH);
11976  }
11977  }
11978  }
11979  else
11980  {
11981  SpeedVariableLabel->Caption = "";
11982  }
11983  Utilities->CallLogPop(1865);
11984  }
11985  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11986  {
11987  SpeedVariableLabel->Caption = "Entry error";
11988  }
11989  catch(const Exception &e)
11990  {
11991  ErrorLog(176, e.Message);
11992  }
11993 }
11994 
11995 // ---------------------------------------------------------------------------
11996 
11997 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
11998 {
11999  if(PowerTopLabel->Caption == "HP")
12000  {
12001  PowerTopLabel->Caption = "kW";
12002  PowerBottomLabel->Caption = "HP";
12003  }
12004  else
12005  {
12006  PowerTopLabel->Caption = "HP";
12007  PowerBottomLabel->Caption = "kW";
12008  }
12009  // swap values to match toggle state
12010  UnicodeString SavedTopValue = PowerEditBox->Text;
12011  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
12012 
12013  PowerEditBox->Text = SavedBottomValue;
12014  PowerVariableLabel->Caption = SavedTopValue;
12015 }
12016 // ---------------------------------------------------------------------------
12017 
12018 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12019 {
12020  try
12021  {
12022  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
12023  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
12024  bool ErrorFlag = false, TooBigFlag = false;
12025  if(PowerEditBox->Text.Length() > 0)
12026  {
12027  if(PowerEditBox->Text.Length() > 8)
12028  {
12029  TooBigFlag = true;
12030  }
12031  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
12032  {
12033  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
12034  {
12035  PowerVariableLabel->Caption = "Entry error";
12036  ErrorFlag = true;
12037  break;
12038  }
12039  if(TooBigFlag)
12040  {
12041  PowerVariableLabel->Caption = "Too big";
12042  break;
12043  }
12044  }
12045  if(!ErrorFlag && !TooBigFlag)
12046  {
12047 /*
12048  1 kW = 1.340482574 HP
12049  1 HP = 0.745699872 kW
12050 */
12051  if(PowerTopLabel->Caption == "HP")
12052  {
12053  // do HP-to-kW conv
12054  int HP = PowerEditBox->Text.ToInt();
12055  int KW = (HP * 0.745699872) + 0.5;
12056  PowerVariableLabel->Caption = UnicodeString(KW);
12057  }
12058  else
12059  {
12060  // do kW-to-HP conv
12061  int KW = PowerEditBox->Text.ToInt();
12062  int HP = (KW * 1.340482574) + 0.5;
12063  PowerVariableLabel->Caption = UnicodeString(HP);
12064  }
12065  }
12066  }
12067  else
12068  {
12069  PowerVariableLabel->Caption = "";
12070  }
12071  Utilities->CallLogPop(1868);
12072  }
12073  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
12074  {
12075  PowerVariableLabel->Caption = "Entry error";
12076  }
12077  catch(const Exception &e)
12078  {
12079  ErrorLog(179, e.Message);
12080  }
12081 }
12082 // ---------------------------------------------------------------------------
12083 
12084 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12085 {
12086  try
12087  {
12088  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
12089  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
12090  bool ErrorFlag = false, TooBigFlag = false;
12091  if(SpeedEditBox2->Text.Length() > 0)
12092  {
12093  if(SpeedEditBox2->Text.Length() > 5)
12094  {
12095  TooBigFlag = true;
12096  }
12097  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
12098  {
12099  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
12100  {
12101  SpeedVariableLabel2->Caption = "Entry error";
12102  ErrorFlag = true;
12103  break;
12104  }
12105  if(TooBigFlag)
12106  {
12107  SpeedVariableLabel2->Caption = "Too big";
12108  break;
12109  }
12110  }
12111  if(!ErrorFlag && !TooBigFlag)
12112  {
12113 /*
12114  1 mph = 1.609344 km/h
12115  1 km/h = 0.621371 mph
12116 */
12117  if(SpeedTopLabel2->Caption == "mph")
12118  {
12119  // do mph-to-km/h conversion
12120  int MPH = SpeedEditBox2->Text.ToInt();
12121  int KPH = (MPH * 1.609344) + 0.5;
12122  SpeedVariableLabel2->Caption = AnsiString(KPH);
12123  }
12124  else
12125  {
12126  // do km/h-to-mph conversion
12127  int KPH = SpeedEditBox2->Text.ToInt();
12128  int MPH = (KPH * 0.621371) + 0.5;
12129  SpeedVariableLabel2->Caption = AnsiString(MPH);
12130  }
12131  }
12132  }
12133  else
12134  {
12135  SpeedVariableLabel2->Caption = "";
12136  }
12137  Utilities->CallLogPop(1866);
12138  }
12139  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
12140  {
12141  SpeedVariableLabel2->Caption = "Entry error";
12142  }
12143  catch(const Exception &e)
12144  {
12145  ErrorLog(177, e.Message);
12146  }
12147 }
12148 
12149 // ---------------------------------------------------------------------------
12150 
12151 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12152 {
12153  try
12154  {
12155  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
12156  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
12157  bool ErrorFlag = false, TooLongFlag = false;
12158  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
12159  {
12160  for(int x = 1; x <= MileEdit->Text.Length(); x++)
12161  {
12162  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
12163  {
12164  MetreVariableLabel->Caption = "Entry error";
12165  ErrorFlag = true;
12166  break;
12167  }
12168  }
12169  }
12170  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
12171  {
12172  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
12173  {
12174  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
12175  {
12176  MetreVariableLabel->Caption = "Entry error";
12177  ErrorFlag = true;
12178  break;
12179  }
12180  }
12181  }
12182  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
12183  {
12184  for(int x = 1; x <= YardEdit->Text.Length(); x++)
12185  {
12186  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
12187  {
12188  MetreVariableLabel->Caption = "Entry error";
12189  ErrorFlag = true;
12190  break;
12191  }
12192  }
12193  }
12194  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
12195  {
12196  TooLongFlag = true;
12197  MetreVariableLabel->Caption = "Too big";
12198  }
12199  if(!ErrorFlag && !TooLongFlag)
12200  {
12201  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
12202  if(MileEdit->Text.Length() > 0)
12203  {
12204  Miles = MileEdit->Text.ToInt();
12205  }
12206  if(ChainEdit->Text.Length() > 0)
12207  {
12208  Chains = ChainEdit->Text.ToInt();
12209  }
12210  if(YardEdit->Text.Length() > 0)
12211  {
12212  Yards = YardEdit->Text.ToInt();
12213  }
12214  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
12215  MetreVariableLabel->Caption = AnsiString(Metres);
12216  }
12217  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
12218  {
12219  MetreVariableLabel->Caption = "";
12220  }
12221  Utilities->CallLogPop(1867);
12222  }
12223  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
12224  {
12225  MetreVariableLabel->Caption = "Entry error";
12226  }
12227  catch(const Exception &e)
12228  {
12229  ErrorLog(178, e.Message);
12230  }
12231 }
12232 
12233 // ---------------------------------------------------------------------------
12234 
12235 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
12236 {
12237  try
12238  {
12239  TrainController->LogEvent("TTClockAdjButtonClick");
12240  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
12241 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
12242  Display->HideWarningLog(0); // because this panel overwrites it
12243  TTClockAdjPanel->Visible = true;
12244  TTClockAdjButton->Enabled = false;
12245 /*
12246  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
12247  OperatingPanel->Enabled = false;
12248  ZoomButton->Enabled = false;
12249  HomeButton->Enabled = false;
12250  NewHomeButton->Enabled = false;
12251  ScreenLeftButton->Enabled = false;
12252  ScreenRightButton->Enabled = false;
12253  ScreenUpButton->Enabled = false;
12254  ScreenDownButton->Enabled = false;
12255 */
12256  Utilities->CallLogPop(1875);
12257  }
12258  catch(const Exception &e)
12259  {
12260  ErrorLog(181, e.Message);
12261  }
12262 }
12263 
12264 // ---------------------------------------------------------------------------
12265 
12266 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
12267 {
12268  try
12269  {
12270  TrainController->LogEvent("TTClockExitButtonClick");
12271  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
12272  TTClockAdjPanel->Visible = false;
12273  TTClockAdjButton->Enabled = true;
12274 /* these dealt with in ClockTimer2
12275  ZoomButton->Enabled = true;
12276  HomeButton->Enabled = true;
12277  NewHomeButton->Enabled = true;
12278  ScreenLeftButton->Enabled = true;
12279  ScreenRightButton->Enabled = true;
12280  ScreenUpButton->Enabled = true;
12281  ScreenDownButton->Enabled = true;
12282  OperatingPanel->Enabled = true;
12283  OperatingPanelLabel->Caption = "Operation";
12284 */
12285  Display->ShowWarningLog(0);
12286  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
12287  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
12288  {
12289  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
12291  {
12292  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height) / 2);
12293  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width) / 2);
12294  TTClockAdjustWarningLabel->Caption =
12295  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
12296  TTClockAdjustWarningPanel->Visible = true;
12297  }
12298  }
12299 // Utilities->Clock2Stopped = false; // as above
12301 // to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
12302  Utilities->CallLogPop(1876);
12303  }
12304  catch(const Exception &e)
12305  {
12306  ErrorLog(182, e.Message);
12307  }
12308 }
12309 // ---------------------------------------------------------------------------
12310 
12311 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
12312 {
12313  try
12314  {
12315  TrainController->LogEvent("TTClockx2ButtonClick");
12316  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
12317  TTClockSpeed = 2;
12318  TTClockSpeedLabel->Caption = "x2";
12320  Utilities->CallLogPop(1878);
12321  }
12322  catch(const Exception &e)
12323  {
12324  ErrorLog(184, e.Message);
12325  }
12326 }
12327 
12328 // ---------------------------------------------------------------------------
12329 
12330 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
12331 {
12332  try
12333  {
12334  TrainController->LogEvent("TTClockx4ButtonClick");
12335  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
12336  TTClockSpeed = 4;
12337  TTClockSpeedLabel->Caption = "x4";
12339  Utilities->CallLogPop(1883);
12340  }
12341  catch(const Exception &e)
12342  {
12343  ErrorLog(189, e.Message);
12344  }
12345 }
12346 
12347 // ---------------------------------------------------------------------------
12348 
12349 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
12350 {
12351  try
12352  {
12353  TrainController->LogEvent("TTClockx8ButtonClick");
12354  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
12355  TTClockSpeed = 8;
12356  TTClockSpeedLabel->Caption = "x8";
12358  Utilities->CallLogPop(1884);
12359  }
12360  catch(const Exception &e)
12361  {
12362  ErrorLog(190, e.Message);
12363  }
12364 }
12365 
12366 // ---------------------------------------------------------------------------
12367 
12368 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
12369 {
12370  try
12371  {
12372  TrainController->LogEvent("TTClockx16ButtonClick");
12373  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
12374  TTClockSpeed = 16;
12375  TTClockSpeedLabel->Caption = "x16";
12377  Utilities->CallLogPop(1885);
12378  }
12379  catch(const Exception &e)
12380  {
12381  ErrorLog(191, e.Message);
12382  }
12383 }
12384 
12385 // ---------------------------------------------------------------------------
12386 
12387 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
12388 {
12389  try
12390  {
12391  TrainController->LogEvent("TTClockx1ButtonClick");
12392  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
12393  TTClockSpeed = 1;
12394  TTClockSpeedLabel->Caption = "x1";
12396  Utilities->CallLogPop(1886);
12397  }
12398  catch(const Exception &e)
12399  {
12400  ErrorLog(192, e.Message);
12401  }
12402 }
12403 
12404 // ---------------------------------------------------------------------------
12405 
12406 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
12407 {
12408  try
12409  {
12410  TrainController->LogEvent("TTClockxHalfButtonClick");
12411  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
12412  TTClockSpeed = 0.5;
12413  TTClockSpeedLabel->Caption = "x1/2";
12415  Utilities->CallLogPop(1887);
12416  }
12417  catch(const Exception &e)
12418  {
12419  ErrorLog(193, e.Message);
12420  }
12421 }
12422 
12423 // ---------------------------------------------------------------------------
12424 
12425 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
12426 {
12427  try
12428  {
12429  TrainController->LogEvent("TTClockxQuarterButtonClick");
12430  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
12431  TTClockSpeed = 0.25;
12432  TTClockSpeedLabel->Caption = "x1/4";
12434  Utilities->CallLogPop(1888);
12435  }
12436  catch(const Exception &e)
12437  {
12438  ErrorLog(194, e.Message);
12439  }
12440 }
12441 
12442 // ---------------------------------------------------------------------------
12443 
12444 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
12445 {
12446  // added for v2.3.0 for very big railways
12447  try
12448  {
12449  TrainController->LogEvent("TTClockxEighthButtonClick");
12450  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
12451  TTClockSpeed = 0.125;
12452  TTClockSpeedLabel->Caption = "x1/8";
12454  Utilities->CallLogPop(2099);
12455  }
12456  catch(const Exception &e)
12457  {
12458  ErrorLog(203, e.Message);
12459  }
12460 }
12461 // ---------------------------------------------------------------------------
12462 
12463 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
12464 {
12465  // added for v2.3.0 for very big railways
12466  try
12467  {
12468  TrainController->LogEvent("TTClockxSixteenthButtonClick");
12469  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
12470  TTClockSpeed = 0.0625;
12471  TTClockSpeedLabel->Caption = "x1/16";
12473  Utilities->CallLogPop(2100);
12474  }
12475  catch(const Exception &e)
12476  {
12477  ErrorLog(204, e.Message);
12478  }
12479 }
12480 
12481 // ---------------------------------------------------------------------------
12482 
12483 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
12484 {
12485  try
12486  {
12487  TrainController->LogEvent("TTClockAdd1hButtonClick");
12488  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
12489  double TTClockIncrement = 1.0 / 24;
12490  TrainController->RestartTime += TDateTime(TTClockIncrement);
12493  Utilities->CallLogPop(1879);
12494  }
12495  catch(const Exception &e)
12496  {
12497  ErrorLog(185, e.Message);
12498  }
12499 }
12500 
12501 // ---------------------------------------------------------------------------
12502 
12503 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
12504 {
12505  try
12506  {
12507  TrainController->LogEvent("TTClockAdd10mButtonClick");
12508  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
12509  double TTClockIncrement = 1.0 / 144;
12510  TrainController->RestartTime += TDateTime(TTClockIncrement);
12513  Utilities->CallLogPop(1881);
12514  }
12515  catch(const Exception &e)
12516  {
12517  ErrorLog(187, e.Message);
12518  }
12519 }
12520 
12521 // ---------------------------------------------------------------------------
12522 
12523 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
12524 {
12525  try
12526  {
12527  TrainController->LogEvent("TTClockAdd1mButtonClick");
12528  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
12529  double TTClockIncrement = 1.0 / 1440;
12530  TrainController->RestartTime += TDateTime(TTClockIncrement);
12533  Utilities->CallLogPop(1882);
12534  }
12535  catch(const Exception &e)
12536  {
12537  ErrorLog(188, e.Message);
12538  }
12539 }
12540 
12541 // ---------------------------------------------------------------------------
12542 
12543 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
12544 {
12545  try
12546  {
12547  TrainController->LogEvent("TTClockResetButtonClick");
12548  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
12553  if(TTClockSpeed == 2)
12554  {
12555  TTClockSpeedLabel->Caption = "x2";
12556  }
12557  else if(TTClockSpeed == 4)
12558  {
12559  TTClockSpeedLabel->Caption = "x4";
12560  }
12561  else if(TTClockSpeed == 8)
12562  {
12563  TTClockSpeedLabel->Caption = "x8";
12564  }
12565  else if(TTClockSpeed == 16)
12566  {
12567  TTClockSpeedLabel->Caption = "x16";
12568  }
12569  else if(TTClockSpeed == 0.5)
12570  {
12571  TTClockSpeedLabel->Caption = "x1/2";
12572  }
12573  else if(TTClockSpeed == 0.25)
12574  {
12575  TTClockSpeedLabel->Caption = "x1/4";
12576  }
12577  else if(TTClockSpeed == 0.125)
12578  {
12579  TTClockSpeedLabel->Caption = "x1/8";
12580  }
12581  else if(TTClockSpeed == 0.0625)
12582  {
12583  TTClockSpeedLabel->Caption = "x1/16";
12584  }
12585  else
12586  {
12587  TTClockSpeed = 1;
12588  TTClockSpeedLabel->Caption = "x1";
12589  }
12590  Utilities->CallLogPop(1880);
12591  }
12592  catch(const Exception &e)
12593  {
12594  ErrorLog(186, e.Message);
12595  }
12596 }
12597 
12598 // ---------------------------------------------------------------------------
12599 
12600 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
12601 {
12602  try
12603  {
12604  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
12605  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
12606  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
12607  OperatingPanelLabel->Caption = "Disabled";
12608  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
12609  ZoomButton->Enabled = false;
12610  HomeButton->Enabled = false;
12611  NewHomeButton->Enabled = false;
12612  ScreenLeftButton->Enabled = false;
12613  ScreenRightButton->Enabled = false;
12614  ScreenUpButton->Enabled = false;
12615  ScreenDownButton->Enabled = false;
12616 
12617  Screen->Cursor = TCursor(-11); // Hourglass
12618  TPrefDirElement StartElement, EndElement;
12619  bool PointsChanged, AtLeastOneSet = false;
12620  int LastIteratorValue = 0;
12621  while(true)
12622  {
12623  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
12624  {
12625  break;
12626  }
12627  // rest of routine here - i.e. build the routes
12628  ConstructRoute->ClearRoute(); // in case not empty though should be
12629  AtLeastOneSet = true;
12630  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true)) // true for AutoSigsFlag
12631  {
12632  }
12633  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
12634  PointsChanged))
12635  {
12636  }
12638  }
12639  if(AtLeastOneSet)
12640  {
12643  }
12644  else
12645  {
12646  ShowMessage("No presettable automatic signal routes are available");
12647  }
12648  Screen->Cursor = TCursor(-2); // Arrow
12649  Utilities->CallLogPop(1994);
12650  }
12651  catch(const Exception &e)
12652  {
12653  ErrorLog(195, e.Message);
12654  }
12655 }
12656 
12657 // ---------------------------------------------------------------------------
12658 
12659 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
12660 {
12661  try
12662  {
12663  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
12664  {
12665  // else fails on shutdown because HiddenScreen & other things no longer exist
12666  int DispW = (Interface->Width - 64 - 16) / 16;
12667 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
12668  int DispH = (Interface->Height - 192) / 16;
12669  MainScreen->Width = DispW * 16;
12670  MainScreen->Height = DispH * 16;
12671  Utilities->ScreenElementWidth = DispW;
12672  Utilities->ScreenElementHeight = DispH;
12673  HiddenScreen->Width = MainScreen->Width;
12674  HiddenScreen->Height = MainScreen->Height;
12675  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
12676  PerformancePanel->Left = MainScreen->Left;
12677  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
12678  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
12679  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
12680  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
12681  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
12682  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
12683  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
12684  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
12685  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
12686  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
12687 
12688  if(!Display->ZoomOutFlag)
12689  {
12691  }
12692  else
12693  {
12694  Display->ClearDisplay(11);
12696  }
12697  Display->Update();
12698  }
12699  }
12700  catch(const Exception &e)
12701  {
12702  ErrorLog(197, e.Message);
12703  }
12704 }
12705 
12706 // ---------------------------------------------------------------------------
12707 
12708 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
12709 {
12710  try
12711  {
12712  TrainController->LogEvent("OperatorActionButtonClick");
12713  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
12715  {
12716  ShowOperatorActionPanel = true;
12717  OperatorActionPanel->Visible = true;
12719  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
12720  }
12721  else
12722  {
12723  ShowOperatorActionPanel = false;
12724  OperatorActionPanel->Visible = false;
12726  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
12727  }
12728  Utilities->CallLogPop(2073);
12729  }
12730  catch(const Exception &e)
12731  {
12732  ErrorLog(199, e.Message);
12733  }
12734 }
12735 
12736 // ---------------------------------------------------------------------------
12737 
12739 {
12740  try
12741  {
12742  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
12743  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
12745  if(Utilities->RHSignalFlag) // RH sigs after conversion
12746  {
12747  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
12749  {
12751  }
12752  else
12753  {
12755  }
12756  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
12757  SigsOnLeftImage1->Visible = false;
12758  SigsOnLeftImage2->Visible = false;
12759  SigsOnRightImage1->Visible = true;
12760  SigsOnRightImage2->Visible = true;
12761  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
12762  if(SigFile.fail())
12763  {
12764  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
12765  }
12766  else
12767  {
12768  Utilities->SaveFileString(SigFile, "RHSignals");
12769  }
12770  }
12771  else // LH sigs after conversion
12772  {
12773  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
12775  {
12777  }
12778  else
12779  {
12781  }
12782  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
12783  SigsOnRightImage1->Visible = false;
12784  SigsOnRightImage2->Visible = false;
12785  SigsOnLeftImage1->Visible = true;
12786  SigsOnLeftImage2->Visible = true;
12787  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
12788  if(SigFile.fail())
12789  {
12790  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
12791  }
12792  else
12793  {
12794  Utilities->SaveFileString(SigFile, "LHSignals");
12795  }
12796  }
12797  Utilities->CallLogPop(2097);
12798  }
12799  catch(const Exception &e)
12800  {
12801  ErrorLog(202, e.Message);
12802  }
12803 }
12804 // ---------------------------------------------------------------------------
12805 
12806 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12807 
12808 {
12809  try
12810  {
12811  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
12812  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
12813  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12814  {
12815  Utilities->CallLogPop(2160);
12816  return;
12817  }
12818  bool TooBigFlag = false, BadCharsFlag = false;
12821  if(MTBFEditBox->Text.Length() > 0)
12822  {
12823  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
12824  {
12825  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
12826  {
12827  BadCharsFlag = true;
12828  break;
12829  }
12830  }
12831  if(!BadCharsFlag)
12832  {
12833  if(StrToInt(MTBFEditBox->Text) > 10000)
12834  {
12835  TooBigFlag = true;
12836  }
12837  }
12838  if(TooBigFlag)
12839  {
12840  ShowMessage("Maximum value allowed is 10,000");
12841  MTBFEditBox->Text = "";
12844  Utilities->CallLogPop(2161);
12845  return;
12846  }
12847  if(BadCharsFlag)
12848  {
12849  ShowMessage("Value must be a whole number with no special characters");
12850  MTBFEditBox->Text = "";
12853  Utilities->CallLogPop(2162);
12854  return;
12855  }
12856  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
12858  }
12860  {
12861  MTBFEditBox->Text = "";
12863  }
12864  Utilities->CallLogPop(2163);
12865  }
12866  catch(const Exception &e)
12867  {
12868  ErrorLog(209, e.Message);
12869  }
12870 }
12871 
12872 // ---------------------------------------------------------------------------
12873 
12874 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
12875 {
12876  try
12877  {
12878  TrainController->LogEvent("MTBFEditBoxClick");
12879  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12880  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12881  {
12882  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
12884  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
12885  }
12886  Utilities->CallLogPop(2164);
12887  }
12888  catch(const Exception &e)
12889  {
12890  ErrorLog(210, e.Message);
12891  }
12892 }
12893 
12894 // ---------------------------------------------------------------------------
12895 
12896 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
12897 {
12898  try
12899  {
12900  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12901  LengthConversionPanel->Visible = false;
12902  SpeedConversionPanel->Visible = false;
12903  DistanceKey->Visible = false;
12904  TrackElementPanel->Visible = false;
12905  SigAspectButton->Enabled = false;
12907  SetLevel2TrackMode(63);
12908  Display->Update();
12909  if((SelectedGraphicFileName != "") && (!Track->UserGraphicVector.empty()))
12910  // latter condition added at v2.6.0 because showed after ClearAll & reselect failed
12911  {
12912  UserGraphicReselectPanel->Visible = true;
12913  }
12914  else
12915  {
12916  UserGraphicReselectPanel->Visible = false;
12917  LoadUserGraphic(0);
12918  }
12919  Utilities->CallLogPop(2183);
12920  }
12921  catch(const Exception &e)
12922  {
12923  ErrorLog(212, e.Message);
12924  }
12925 }
12926 
12927 // ---------------------------------------------------------------------------
12928 
12929 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
12930 {
12931  try
12932  {
12933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
12934  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
12935  UserGraphicReselectPanel->Visible = false;
12936  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
12937  if(UGMIt == Track->UserGraphicMap.end())
12938  {
12939  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
12940  Utilities->CallLogPop(2196);
12941  return;
12942  }
12944  SetLevel2TrackMode(64);
12945  Utilities->CallLogPop(2184);
12946  }
12947  catch(const Exception &e)
12948  {
12949  ErrorLog(213, e.Message);
12950  }
12951 }
12952 // ---------------------------------------------------------------------------
12953 
12954 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
12955 {
12956  try
12957  {
12958  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
12959  UserGraphicReselectPanel->Visible = false;
12960  LoadUserGraphic(1);
12961  Utilities->CallLogPop(2185);
12962  }
12963  catch(const Exception &e)
12964  {
12965  ErrorLog(214, e.Message);
12966  }
12967 }
12968 
12969 // ---------------------------------------------------------------------------
12970 
12971 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
12972 {
12973  try
12974  {
12975  TrainController->LogEvent("TTClockAdjustOKButtonClick");
12976  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
12977  TTClockAdjustWarningPanel->Visible = false;
12978  if(TTClockAdjustCheckBox->Checked)
12979  {
12980  TTClockAdjustWarningHide = true;
12981  }
12982  Utilities->CallLogPop(2219);
12983  }
12984  catch(const Exception &e)
12985  {
12986  ErrorLog(216, e.Message);
12987  }
12988 }
12989 
12990 // ---------------------------------------------------------------------------
12991 
12992 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
12993 {
12994  try
12995  {
12996  TrainController->LogEvent("ConflictAnalysisButtonClick");
12997  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
12998  ConflictPanel->Visible = true;
12999  Utilities->CallLogPop(2220);
13000  }
13001  catch(const Exception &e)
13002  {
13003  ErrorLog(217, e.Message);
13004  }
13005 }
13006 
13007 // ---------------------------------------------------------------------------
13008 
13009 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
13010 {
13011  try
13012  {
13013  TrainController->LogEvent("CPCancelButtonClick");
13014  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
13015  ConflictPanel->Visible = false;
13016  Utilities->CallLogPop(2221);
13017  }
13018  catch(const Exception &e)
13019  {
13020  ErrorLog(218, e.Message);
13021  }
13022 }
13023 
13024 // ---------------------------------------------------------------------------
13025 
13026 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
13027 {
13028  try
13029  {
13030  TrainController->LogEvent("CPGenFileButtonClick");
13031  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
13032  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked)
13033  {
13034  ShowMessage("No boxes ticked!");
13035  }
13036  else // keep ticks & range values from last time, only reset on startup
13037  {
13038  Screen->Cursor = TCursor(-11); // hourglass
13039  AnsiString TTTitle;
13041  {
13042  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
13043  {
13044  if(CreateEditTTFileName[x] == '\\')
13045  {
13046  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
13047  break;
13048  }
13049  }
13051  CPAtLocCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
13052  {
13053  ShowMessage("Analysis complete and file created");
13054  }
13055  ConflictPanel->Visible = false;
13056  }
13057  }
13058  Screen->Cursor = TCursor(-2); // arrow
13059  Utilities->CallLogPop(2222);
13060  }
13061  catch(const Exception &e)
13062  {
13063  ErrorLog(219, e.Message);
13064  }
13065 }
13066 
13067 // ---------------------------------------------------------------------------
13068 // end of fastcalls & directly associated functions
13069 // ---------------------------------------------------------------------------
13070 
13071 void TInterface::SetTopIndex(int Caller)
13072 {
13073 // Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
13074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
13075  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
13076  {
13078  }
13079  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
13080  {
13081  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
13082  }
13083  else
13084  {
13085  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
13086  }
13087  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
13088  Utilities->CallLogPop(2207);
13089 }
13090 
13091 // ---------------------------------------------------------------------------
13092 
13093 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
13094 {
13095  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
13096  bool ClockState = Utilities->Clock2Stopped;
13097 
13098  Utilities->Clock2Stopped = true;
13100  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
13101  if(ScreenGridFlag && (Level1Mode == TrackMode))
13102  {
13103  int WidthNum = int(MainScreen->Width / 160) + 1;
13104  int HeightNum = int(MainScreen->Height / 144) + 1;
13105  for(int x = 0; x < WidthNum; x++)
13106  {
13107  for(int y = 0; y < HeightNum; y++)
13108  {
13109  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
13110  }
13111  }
13112  }
13113 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
13114 // elements but before active elements. This is so text can overwite stations and non-station named locations.
13115 
13117 
13118 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
13119 // used to occur frequently without Disp->Update() in PlotOriginal
13120 
13121  // OperMode LCs plotted below
13123  {
13125  }
13126  if(Level1Mode == PrefDirMode)
13127  {
13128  if(EveryPrefDir->PrefDirSize() > 0)
13129  {
13131  }
13133  {
13135  }
13136  }
13137  if(Level1Mode == TrackMode)
13138  {
13140  {
13141  LocationNameButton->Enabled = true;
13142  }
13143  else
13144  {
13145  LocationNameButton->Enabled = false;
13146  }
13147  }
13149  {
13151  DistanceKey->Visible = true;
13152  DistancesMarked = true;
13153  LengthConversionPanel->Visible = true;
13154  SpeedConversionPanel->Visible = true;
13155  }
13156  if(Level2TrackMode == DistanceContinuing) // for extended distances
13157  {
13158  if(ConstructPrefDir->PrefDirSize() > 0)
13159  {
13161 // this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
13163  DistanceKey->Visible = true;
13164  DistancesMarked = true;
13165  LengthConversionPanel->Visible = true;
13166  SpeedConversionPanel->Visible = true;
13167  }
13168  }
13170  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
13171  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
13172  {
13174  DistanceKey->Visible = true;
13175  }
13177  // cancel DistancesMarked if exit from any of these modes
13178  {
13179  DistancesMarked = false;
13180  DistanceKey->Visible = false;
13181  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
13182  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
13183  }
13185  // in process of moving so use NewSelectBitmapHLoc & VLoc
13186  {
13188  }
13189 
13191  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
13192  {
13194  }
13195  if(Level1Mode == OperMode)
13196  {
13198  if(!AllRoutes->LockedRouteVector.empty())
13199  {
13200  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
13201  {
13202  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
13203  {
13204  AllRoutes->LockedRouteVector.erase(LRVIT);
13205  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
13206  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
13207  // route being on the other track of a 2-track element doesn't arise)
13208  continue;
13209  }
13210  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
13211  int x = Route.PrefDirSize() - 1;
13212  bool BreakFlag = false;
13213  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
13214  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
13215  {
13216  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
13217  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
13218  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
13219  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
13220  {
13221  BreakFlag = true;
13222  break; // train removed earlier element from route so stop here
13223  }
13224  x--;
13225  if(x < 0) // added after Albie Vowles reported error on 14/08/20 by email
13226  {
13227  // it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
13228  BreakFlag = true;
13229 // at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
13230  break; // it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
13231  }
13232  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
13233  }
13234  if(!BreakFlag)
13235  {
13236  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
13237  {
13238  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
13239  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
13240  }
13241  }
13242  }
13243  }
13244  if(RouteMode == RouteContinuing)
13245  {
13247 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
13250  if(AutoSigsFlag)
13251  {
13253  }
13254  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
13255  {
13257  }
13258  else
13259  {
13261  }
13262  }
13263  if(Track->PointFlashFlag)
13264  {
13265  // need to reset the screen location for picking up the original graphic
13266  int Left, Top; // Embarcadero change - these missing in error from Borland file
13268  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
13269  PointFlash->SetSourceRect(Left, Top);
13270  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
13271  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
13272  }
13273  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
13274  // In order to avoid plotting the whole LC for every element of a LC a bool value - LCPlotted - is used to save time
13275  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
13276  {
13277  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->LCPlotted = false;
13278  }
13279  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
13280  {
13281  int BaseSpeedTag;
13282  TTrackElement ATE;
13283  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
13284  {
13285  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
13286  if(ITE.LCPlotted == false)
13287  {
13288  if(ITE.Attribute == 0)
13289  {
13291  }
13292  else if(ITE.Attribute == 1)
13293  {
13294  // need to determine if should plot green (manual) or red (auto), but all linked LCs have ConsecSignals set to 2 in BarriersDownVector if manual
13295  // so just need to test this for the HLoc & VLoc position match
13296  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
13297  {
13298  if((Track->BarriersDownVector.at(x).HLoc == ITE.HLoc) && (Track->BarriersDownVector.at(x).VLoc == ITE.VLoc))
13299  {
13300  if(Track->BarriersDownVector.at(x).TypeOfRoute == 2)
13301  {
13303  true); // true for manual = green
13304  }
13305  else
13306  {
13308  false); // false for auto = red
13309  }
13310  }
13311  }
13312  }
13313  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting,
13314  // it won't set LCPlotted but no real time lost in this case
13315  }
13316  }
13317  }
13319  }
13320  Display->ZoomOutFlag = false;
13321  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
13322  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
13323  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
13324  Utilities->Clock2Stopped = ClockState;
13325  Utilities->CallLogPop(91);
13326 }
13327 
13328 // ---------------------------------------------------------------------------
13329 
13330 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
13331 {
13332  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
13333  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
13334  {
13335  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
13336  {
13337  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
13338  {
13339  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
13340  }
13342  {
13344  }
13345  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
13346  {
13347  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
13348  }
13350  {
13352  }
13353  }
13354  InfoPanel->Visible = true;
13355  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
13356  ClearandRebuildRailway(31); // get rid of earlier gap selection
13357  Utilities->CallLogPop(92);
13358  return(true); // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
13359  }
13360  Utilities->CallLogPop(93);
13361  return(false); // no unset ones left to find
13362 }
13363 
13364 // ---------------------------------------------------------------------------
13365 
13367 {
13368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
13369  if(FileChangedFlag)
13370  {
13371  UnicodeString MessageStr = "The railway has changed, close it without saving?";
13372  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13373  if(button == IDNO)
13374  {
13375  Utilities->CallLogPop(1140);
13376  return(false);
13377  }
13378  }
13379  Display->ClearDisplay(7);
13381 
13382  Display->DisplayOffsetH = 0;
13383  Display->DisplayOffsetV = 0;
13388 
13389 // these ensure that all persistent vectors, maps & multimaps etc are cleared
13390  delete TrainController;
13391  delete EveryPrefDir;
13392  delete ConstructRoute;
13393  delete ConstructPrefDir;
13394  delete AllRoutes;
13395  delete Track;
13396  delete TextHandler;
13397 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
13398 // pop earlier pushed values
13399 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
13400 // railway
13401  TextHandler = new TTextHandler;
13402  Track = new TTrack;
13403  AllRoutes = new TAllRoutes;
13405  ConstructRoute = new TOneRoute;
13406  EveryPrefDir = new TOnePrefDir;
13408  PerformanceLogBox->Lines->Clear();
13409  ResetAll(1);
13410  Utilities->CallLogPop(94);
13411  return(true);
13412 }
13413 
13414 // ---------------------------------------------------------------------------
13415 
13416 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
13417 {
13418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
13419  std::ifstream VecFile(FileName);
13420 
13421  if(VecFile.is_open())
13422  {
13423  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
13424  {
13425  VecFile.close();
13426  Utilities->CallLogPop(1805);
13427  return(false);
13428  }
13429  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
13430  {
13431  VecFile.close();
13432  Utilities->CallLogPop(1440);
13433  return(false);
13434  }
13435  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
13436  {
13437  VecFile.close();
13438  Utilities->CallLogPop(1441);
13439  return(false);
13440  }
13441  bool GraphicsFollow = false;
13442  int NumberOfActiveElements;
13443  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
13444  {
13445  VecFile.close();
13446  Utilities->CallLogPop(95);
13447  return(false);
13448  }
13449  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
13450  {
13451  VecFile.close();
13452  Utilities->CallLogPop(96);
13453  return(false);
13454  }
13455  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
13456  {
13457  VecFile.close();
13458  Utilities->CallLogPop(97);
13459  return(false);
13460  }
13461  if(GraphicsFollow)
13462  {
13463  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
13464  {
13465  VecFile.close();
13466  Utilities->CallLogPop(2186);
13467  return(false);
13468  }
13469  }
13470  VecFile.close();
13471  }
13472  else
13473  {
13474  Utilities->CallLogPop(1153);
13475  return(false);
13476  }
13477  Utilities->CallLogPop(98);
13478  return(true);
13479 }
13480 
13481 // ---------------------------------------------------------------------------
13482 
13483 void TInterface::Delay(int Caller, double Msec)
13484 {
13485  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
13486  TDateTime First, Second;
13487  bool Finished = false;
13488 
13489  First = TDateTime::CurrentDateTime();
13490  double TimeVal1 = 86400000 * double(First); // no of msec in a day
13491 
13492  while(!Finished)
13493  {
13494  Second = TDateTime::CurrentDateTime();
13495  double TimeVal2 = 86400000 * double(Second);
13496  if((TimeVal2 - TimeVal1) > Msec)
13497  {
13498  Finished = true;
13499  }
13500  }
13501  Utilities->CallLogPop(1203);
13502 }
13503 
13504 // ---------------------------------------------------------------------------
13505 
13507 {
13508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
13509  if(CurrentSpeedButton)
13510  {
13511  CurrentSpeedButton->Down = false;
13512  }
13513  CurrentSpeedButton = 0;
13514  Utilities->CallLogPop(1204);
13515 }
13516 
13517 // ---------------------------------------------------------------------------
13518 
13520 {
13521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
13522  int TrainID;
13523 
13524  if(ConstructRoute->SearchVectorSize() == 0)
13525  {
13526  Utilities->CallLogPop(99);
13527  return(false);
13528  }
13529  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
13530  {
13531  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
13532  if(PrefDirElement.TrackType == Bridge)
13533  {
13534  if(PrefDirElement.GetXLinkPos() < 2)
13535  {
13536  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
13537  }
13538  else
13539  {
13540  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
13541  }
13542  }
13543  else
13544  {
13545  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
13546  }
13547  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
13548  {
13549  Utilities->CallLogPop(100);
13550  return(true);
13551  }
13552  // check for crossed diagonal fouling by train added at v1.2.0
13553  int TrainID; // not used
13554  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
13555  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
13556  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
13557  {
13558  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
13559  {
13560  Utilities->CallLogPop(2037);
13561  return(true);
13562  }
13563  }
13564  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
13565  {
13566  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
13567  {
13568  Utilities->CallLogPop(2038);
13569  return(true);
13570  }
13571  }
13572  }
13573  Utilities->CallLogPop(101);
13574  return(false);
13575 }
13576 
13577 // ---------------------------------------------------------------------------
13578 
13580 {
13581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
13582  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
13583  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
13584  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
13585  RouteCancelFlag = false;
13587  {
13588  RouteCancelButton->Enabled = true;
13589  }
13590  else
13591  {
13592  RouteCancelButton->Enabled = false;
13593  }
13596 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
13597  InfoPanel->Visible = true;
13598  if(Level2OperMode != Paused)
13599  {
13600  InfoPanel->Caption = InfoCaptionStore;
13601  }
13602  Utilities->CallLogPop(102);
13603 }
13604 
13605 // ---------------------------------------------------------------------------
13606 
13607 // usermode functions below
13609 {
13610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
13611  if(!Display->ZoomOutFlag)
13612  {
13615  Track->GapFlashFlag = false;
13616  }
13617 // GapFlash resets when any mode selected unless zoomed out
13618 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
13619 // reset GapFlashFlag
13620  switch(Level1Mode) // use the data member
13621  {
13622  case BaseMode:
13623  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
13624  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
13625  PasteMenuItem->ShortCut = TextToShortCut("");
13630  LengthConversionPanel->Visible = false;
13631  SpeedConversionPanel->Visible = false;
13632  TimetableEditPanel->Visible = false;
13633  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
13634  TrackBuildPanel->Visible = false;
13635  TrackElementPanel->Visible = false;
13636  LocationNameTextBox->Visible = false;
13637  TextBox->Visible = false;
13638  TrackLengthPanel->Visible = false;
13639  InfoPanel->Visible = false;
13640  PrefDirPanel->Visible = false;
13641  TimetablePanel->Visible = false;
13642  OperatingPanel->Visible = false;
13643  PrefDirKey->Visible = false;
13644  TrackLinkedImage->Visible = false;
13645  TrackNotLinkedImage->Visible = false;
13646  GapsSetImage->Visible = false;
13647  GapsNotSetImage->Visible = false;
13648  LocationNamesSetImage->Visible = false;
13649  LocationNamesNotSetImage->Visible = false;
13650  ModeMenu->Enabled = true;
13651  FileMenu->Enabled = true;
13652  EditMenu->Enabled = false;
13653  BuildTrackMenuItem->Enabled = true;
13654  SigAspectButton->Enabled = false;
13655  Track->ChangingLCVector.clear();
13656  Track->BarriersDownVector.clear();
13658  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
13659  SigImagePanel->Visible = false; // new at v2.3.0
13660  MTBFEditBox->Visible = false; // new at v2.4.0
13661  MTBFLabel->Visible = false;
13662  TTClockAdjustWarningPanel->Visible = false;
13663  if(Track->IsTrackFinished())
13664  {
13665  PlanPrefDirsMenuItem->Enabled = true;
13666  if(TimetableTitle != "")
13667  {
13668  OperateRailwayMenuItem->Enabled = true;
13669  }
13670  else
13671  {
13672  OperateRailwayMenuItem->Enabled = false;
13673  }
13674  }
13675  else
13676  {
13677  PlanPrefDirsMenuItem->Enabled = false;
13678  OperateRailwayMenuItem->Enabled = false;
13679  }
13680  if(RlyFile)
13681  {
13682  LoadTimetableMenuItem->Enabled = true;
13683  }
13684  else
13685  {
13686  LoadTimetableMenuItem->Enabled = false;
13687  }
13688  LoadRailwayMenuItem->Enabled = true;
13689  if(NoRailway())
13690  {
13691  SaveAsMenuItem->Enabled = false;
13692  ImageMenu->Enabled = false;
13693  SaveImageAndGridMenuItem->Enabled = false;
13694  SaveImageNoGridMenuItem->Enabled = false;
13695  SaveImageAndPrefDirsMenuItem->Enabled = false;
13696  SaveOperatingImageMenuItem->Enabled = false;
13697  BlackBgndMenuItem->Enabled = false;
13698  WhiteBgndMenuItem->Enabled = false;
13699  BlueBgndMenuItem->Enabled = false;
13700  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
13701  SigImagePanel->Visible = true; // new at v2.3.0
13702  if(Utilities->clTransparent != TColor(0))
13703  {
13704  BlackBgndMenuItem->Enabled = true;
13705  }
13706  if(Utilities->clTransparent != TColor(0xFFFFFF))
13707  {
13708  WhiteBgndMenuItem->Enabled = true;
13709  }
13710  if(Utilities->clTransparent != TColor(0x330000))
13711  {
13712  BlueBgndMenuItem->Enabled = true;
13713  }
13714  ClearAllMenuItem->Enabled = false;
13715  InfoPanel->Visible = true;
13716  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
13717  }
13718  else
13719  {
13720  InfoPanel->Visible = false;
13721  SaveAsMenuItem->Enabled = true;
13722  ImageMenu->Enabled = true;
13723  SaveImageAndGridMenuItem->Enabled = true;
13724  SaveImageNoGridMenuItem->Enabled = true;
13725  if(EveryPrefDir->PrefDirSize() > 0)
13726  {
13727  SaveImageAndPrefDirsMenuItem->Enabled = true;
13728  }
13729  else
13730  {
13731  SaveImageAndPrefDirsMenuItem->Enabled = false;
13732  }
13733  BlackBgndMenuItem->Enabled = false;
13734  WhiteBgndMenuItem->Enabled = false;
13735  BlueBgndMenuItem->Enabled = false;
13736  SaveOperatingImageMenuItem->Enabled = false;
13737  ClearAllMenuItem->Enabled = true;
13738  }
13739  if(SavedFileName == "")
13740  {
13741  SaveMenuItem->Enabled = false;
13742  }
13743  else if(!FileChangedFlag)
13744  {
13745  SaveMenuItem->Enabled = false;
13746  }
13747  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
13748  {
13749  if(!(Track->IsReadyForOperation(false)))
13750  {
13751  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
13752  }
13753  else
13754  {
13755  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
13756  }
13757  }
13758  else
13759  {
13760  SaveMenuItem->Enabled = true;
13761  }
13762  LoadSessionMenuItem->Enabled = true;
13763  ExitMenuItem->Enabled = true;
13764  ScreenGridFlag = false;
13765  TrainController->CrashWarning = false;
13766  TrainController->DerailWarning = false;
13767  TrainController->SPADWarning = false;
13769  TrainController->CallOnWarning = false;
13772  UserGraphicReselectPanel->Visible = false;
13773  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
13774  SetTrackBuildImages(13);
13775  ClipboardChecked = false;
13776  break;
13777 
13778  case TimetableMode:
13782  ModeMenu->Enabled = false;
13783  SigImagePanel->Visible = false; // new at v2.3.0
13784  FileMenu->Enabled = false;
13785  EditMenu->Enabled = false;
13786  FloatingInfoMenu->Enabled = false;
13787  ImageMenu->Enabled = false;
13788  TimetableEditPanel->BringToFront();
13789  TimetableHandler();
13790  break;
13791 
13792  case TrackMode:
13793  {
13794  if(Level2TrackMode == CutMoving)
13795  {
13796  Level2TrackMode = Pasting; // paste the selection
13797  SetLevel2TrackMode(52); // CancelSelectionFlag used in Case Pasting
13798  }
13803  TrackBuildPanel->Visible = true;
13804  TrackBuildPanelLabel->Caption = "Build/modify";
13805  TrackElementPanel->Visible = false;
13806  TrackLengthPanel->Visible = false;
13807  PrefDirPanel->Visible = false;
13808  TimetablePanel->Visible = false;
13809  OperatingPanel->Visible = false;
13810  InfoPanel->Visible = false;
13811  InfoPanel->Caption = "";
13812  LocationNameTextBox->Visible = false;
13813  TextBox->Visible = false;
13814  ModeMenu->Enabled = false;
13815  SigImagePanel->Visible = false; // new at v2.3.0
13816  FileMenu->Enabled = false;
13817  // set edit menu items
13819  // display track buttons
13820  AddTrackButton->Enabled = true;
13822  {
13823  LocationNameButton->Enabled = true;
13824  }
13825  else
13826  {
13827  LocationNameButton->Enabled = false;
13828  }
13829  ScreenGridButton->Enabled = true;
13830  ExitTrackButton->Enabled = true;
13831  SetGapsButton->Enabled = false;
13832  TrackOKButton->Enabled = false;
13833  if(Track->GapsUnset(5))
13834  {
13835  SetGapsButton->Enabled = true;
13836  }
13837  // only enable if there are gaps still to be set (returns false for no track)
13838  else
13839  {
13840  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
13841  {
13842  TrackOKButton->Enabled = true;
13843  }
13844  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
13845  }
13846  SetLengthsButton->Enabled = false;
13847  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13848  {
13849  SetLengthsButton->Enabled = true;
13850  }
13851  // text buttons
13852  AddTextButton->Enabled = true;
13853  TextOrUserGraphicGridButton->Enabled = true;
13854  FontButton->Enabled = true;
13855  MoveTextOrGraphicButton->Enabled = false;
13856  if(TextHandler->TextVectorSize(9) > 0)
13857  {
13858  MoveTextOrGraphicButton->Enabled = true;
13859  }
13860  if(!Track->UserGraphicVector.empty())
13861  {
13862  MoveTextOrGraphicButton->Enabled = true;
13863  }
13864  SelectionValid = false;
13866  TimetableTitle = "";
13867  SetCaption(0);
13868  } break;
13869 
13870  case PrefDirMode:
13874  PrefDirPanel->Visible = true;
13875  PrefDirPanelLabel->Caption = "Preferred direction selection";
13876 
13877  InfoPanel->Visible = true;
13878  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
13879  PrefDirKey->Visible = true;
13880  ModeMenu->Enabled = false;
13881  SigImagePanel->Visible = false; // new at v2.3.0
13882  FileMenu->Enabled = false;
13883 // set edit menu items
13885  AddPrefDirButton->Enabled = false;
13886  DeleteOnePrefDirButton->Enabled = false;
13888  if(EveryPrefDir->PrefDirSize() > 0)
13889  {
13890  DeleteAllPrefDirButton->Visible = true;
13891  DeleteAllPrefDirButton->Enabled = true;
13892  SaveImageAndPrefDirsMenuItem->Enabled = true;
13893  }
13894  else
13895  {
13896  DeleteAllPrefDirButton->Enabled = false;
13897  SaveImageAndPrefDirsMenuItem->Enabled = false;
13898  }
13899  ExitPrefDirButton->Enabled = true;
13900  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
13901 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
13902 // SetCaption();
13903  break;
13904 
13905  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
13909  OperatingPanel->Visible = true;
13910  OperatingPanelLabel->Caption = "Operation";
13911 
13912  CallingOnButton->Visible = false;
13913  PresetAutoSigRoutesButton->Visible = true;
13914  PresetAutoSigRoutesButton->Enabled = true;
13915  InfoPanel->Visible = true;
13916  SigImagePanel->Visible = false; // new at v2.3.0
13917  ModeMenu->Enabled = false;
13918  FileMenu->Enabled = false;
13919  EditMenu->Enabled = false;
13920  ImageMenu->Enabled = true;
13921  SaveImageAndGridMenuItem->Enabled = true;
13922  SaveImageNoGridMenuItem->Enabled = true;
13923  if(EveryPrefDir->PrefDirSize() > 0)
13924  {
13925  SaveImageAndPrefDirsMenuItem->Enabled = true;
13926  }
13927  else
13928  {
13929  SaveImageAndPrefDirsMenuItem->Enabled = false;
13930  }
13931  SaveOperatingImageMenuItem->Enabled = true;
13932  AutoSigsFlag = false;
13933  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
13935  {
13936  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13937  }
13938  else
13939  {
13940  MTBFEditBox->Text = "";
13941  }
13942  MTBFEditBox->ReadOnly = false; // because this is prestart mode
13943  MTBFLabel->Visible = true;
13944  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13946  if(EveryPrefDir->PrefDirSize() > 0)
13947  {
13948  ConsecSignalsRoute = true; // default starting conditions
13949  PreferredRoute = true; // default starting conditions
13950  }
13951  else // no PrefDirs
13952  {
13953  ConsecSignalsRoute = false;
13954  PreferredRoute = false;
13955  }
13956  OperateButton->Enabled = true;
13957  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13958  ExitOperationButton->Enabled = true;
13959  TTClockAdjButton->Enabled = true;
13960  ShowPerformancePanel = false;
13961  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
13962  ShowOperatorActionPanel = false; // new at v2.2.0
13963  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
13964 
13966 
13967  Utilities->Clock2Stopped = false;
13971  TTClockSpeed = 1;
13972  TTClockSpeedLabel->Caption = "x1";
13975 
13976  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
13977  // format "16/06/2009 20:55:17"
13978  // avoid characters in filename:= / \ : * ? " < > |
13979  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
13980 
13981  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
13982  if(Utilities->PerformanceFile.fail())
13983  {
13984  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
13985  " in the folder where the 'Railway.exe' program file resides");
13986  }
13988 // DisableRouteButtons(2); enable route setting or pre-start
13989 // DisablePanelsStoreMainMenuStates();
13990  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
13991  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
13992 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
13993 
13994 // reset all performance indicators
14018 
14019  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
14020  OAListBox->Clear();
14021  OAListBox->Items->Add(L""); // hints for OpActionPanel
14022  OAListBox->Items->Add(L"");
14023  OAListBox->Items->Add(L"");
14024  OAListBox->Items->Add(L"Left click");
14025  OAListBox->Items->Add(L"headcode to");
14026  OAListBox->Items->Add(L"locate train");
14027  OAListBox->Items->Add(L"");
14028  OAListBox->Items->Add(L"");
14029  OAListBox->Items->Add(L"Right click");
14030  OAListBox->Items->Add(L"headcode for");
14031  OAListBox->Items->Add(L"information");
14032  OAListBox->Items->Add(L"");
14033  OAListBox->Items->Add(L"");
14034  OAListBox->Items->Add(L"Left click and");
14035  OAListBox->Items->Add(L"hold grey area");
14036  OAListBox->Items->Add(L"to move panel");
14037 
14038  ClearandRebuildRailway(55); // so points display with one fillet
14039  break;
14040 
14041  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
14042  Level1Mode = OperMode;
14043 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
14046  OperatingPanel->Visible = true;
14047  OperatingPanelLabel->Caption = "Operation";
14048 
14049  CallingOnButton->Visible = true;
14050  PresetAutoSigRoutesButton->Visible = false;
14051  InfoPanel->Visible = true;
14052  ModeMenu->Enabled = false;
14053  SigImagePanel->Visible = false; // new at v2.3.0
14054  FileMenu->Enabled = false;
14055  EditMenu->Enabled = false;
14056  ImageMenu->Enabled = true;
14057  SaveImageAndGridMenuItem->Enabled = true;
14058  SaveImageNoGridMenuItem->Enabled = true;
14059  if(EveryPrefDir->PrefDirSize() > 0)
14060  {
14061  SaveImageAndPrefDirsMenuItem->Enabled = true;
14062  }
14063  else
14064  {
14065  SaveImageAndPrefDirsMenuItem->Enabled = false;
14066  }
14067  SaveOperatingImageMenuItem->Enabled = true;
14068 
14069  OperateButton->Enabled = true;
14070  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
14071  ExitOperationButton->Enabled = true;
14072  TTClockAdjButton->Enabled = true;
14075  if(Level2OperMode == Paused)
14076  {
14077  DisableRouteButtons(3); // could be PreStart or Paused
14078  }
14083  TTClockSpeed = 1;
14084  TTClockSpeedLabel->Caption = "x1";
14086  ShowPerformancePanel = false; // added at v2.2.0
14087  ShowOperatorActionPanel = false; // new at v2.2.0
14088  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
14089  OAListBox->Clear();
14090  OAListBox->Items->Add(L""); // hints for OpActionPanel
14091  OAListBox->Items->Add(L"");
14092  OAListBox->Items->Add(L"");
14093  OAListBox->Items->Add(L"Left click");
14094  OAListBox->Items->Add(L"headcode to");
14095  OAListBox->Items->Add(L"locate train");
14096  OAListBox->Items->Add(L"");
14097  OAListBox->Items->Add(L"");
14098  OAListBox->Items->Add(L"Right click");
14099  OAListBox->Items->Add(L"headcode for");
14100  OAListBox->Items->Add(L"information");
14101  OAListBox->Items->Add(L"");
14102  OAListBox->Items->Add(L"");
14103  OAListBox->Items->Add(L"Left click and");
14104  OAListBox->Items->Add(L"hold grey area");
14105  OAListBox->Items->Add(L"to move panel");
14106  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
14107  {
14108  MTBFEditBox->Visible = true;
14110  {
14111  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
14112  }
14113  else
14114  {
14115  MTBFEditBox->Text = "";
14116  }
14117  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
14118  MTBFLabel->Visible = true;
14119  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14121  }
14122  else
14123  {
14124  MTBFEditBox->Visible = false;
14125  MTBFEditBox->Text = "";
14126  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
14127  MTBFLabel->Visible = false;
14128  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14130  }
14131  break;
14132 
14133  default:
14134  // No further recursion in BaseMode so OK
14135  Level1Mode = BaseMode;
14136  SetLevel1Mode(29);
14137  break;
14138  }
14139  Utilities->CallLogPop(103);
14140 }
14141 
14142 // ---------------------------------------------------------------------------
14143 
14145 {
14146  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
14147  if(Level1Mode != TrackMode)
14148  {
14149  // No further recursion in BaseMode so OK
14150  Level1Mode = BaseMode;
14151  SetLevel1Mode(20);
14152  Utilities->CallLogPop(1115);
14153  return;
14154  }
14156  {
14157  Utilities->CallLogPop(104);
14158  return;
14159  }
14160  switch(Level2TrackMode) // use the data member
14161  {
14162  case AddTrack:
14164  InfoPanel->Visible = true;
14165  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
14166  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
14167  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
14168  TrackElementPanel->Visible = true;
14169  TrackElementPanel->Enabled = true;
14170  SigAspectButton->Visible = true;
14171  SigAspectButton->Enabled = true;
14172  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
14174  SetLengthsButton->Enabled = false;
14175 // section added at v2.8.0 so buttons show correctly after a paste
14176  SetGapsButton->Enabled = false;
14177  TrackOKButton->Enabled = false;
14178  if(Track->GapsUnset(9))
14179  {
14180  SetGapsButton->Enabled = true;
14181  }
14182  // only enable if there are gaps still to be set (returns false for no track)
14183  else
14184  {
14185  if(!(Track->NoActiveTrack(3)) && !(Track->IsTrackFinished()))
14186  {
14187  TrackOKButton->Enabled = true;
14188  }
14189  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
14190  }
14191 // end of 2.8.0 addition
14192  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
14193  {
14194  SetLengthsButton->Enabled = true;
14195  }
14196  UserGraphicReselectPanel->Visible = false;
14197  SelectLengthsFlag = false; // in case still set though probably won't be
14198  EditMenu->Enabled = true; // added at v2.6.0 to allow edits for an empty screen so track elements can fill a selected area
14199  break;
14200 
14201  case AddGraphic:
14202  InfoPanel->Visible = true;
14203  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
14204  break;
14205 
14206  case SelectGraphic:
14207  InfoPanel->Visible = true;
14208  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
14209  break;
14210 
14211  case GapSetting:
14212  int HLoc, VLoc, Count;
14213  Count = Track->NumberOfGaps(0);
14214  if(div(Count, 2).rem == 1) // condition OK
14215  {
14216  ShowMessage("Can't connect, there are an odd number of gaps");
14218  SetLevel1Mode(77);
14220  // No further recursion in AddTrack so OK
14221  SetLevel2TrackMode(40);
14222  Utilities->CallLogPop(105);
14223  return;
14224  }
14225  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
14226  // need to call this here to start gap setting process off,
14227  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
14228  // complete) or no more gaps to be highlighted
14229  {
14230  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
14231  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
14233  SetLevel1Mode(78);
14235  // No further recursion in AddTrack so OK
14236  SetLevel2TrackMode(41);
14237  Utilities->CallLogPop(106);
14238  return; // all gaps set
14239  }
14240  InfoPanel->Visible = true;
14241  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
14242  UserGraphicReselectPanel->Visible = false;
14244  break;
14245 
14246  case AddText:
14247  InfoPanel->Visible = true;
14248  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
14249  if(TextHandler->TextVectorSize(13) > 0)
14250  {
14251  MoveTextOrGraphicButton->Enabled = true;
14252  }
14253  else
14254  {
14255  MoveTextOrGraphicButton->Enabled = false;
14256  }
14257  UserGraphicReselectPanel->Visible = false;
14258  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
14259  break;
14260 
14261  case MoveTextOrGraphic:
14262  InfoPanel->Visible = true;
14263  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
14264  UserGraphicReselectPanel->Visible = false;
14265  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
14266  break;
14267 
14268  case AddLocationName:
14269  InfoPanel->Visible = true;
14270  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
14271  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
14272  UserGraphicReselectPanel->Visible = false;
14273  SetTrackBuildImages(12);
14274  break;
14275 
14276  case DistanceStart:
14277  InfoPanel->Visible = true;
14278  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
14279  DistanceKey->Visible = true;
14280  LengthConversionPanel->Visible = true;
14281  SpeedConversionPanel->Visible = true;
14282  UserGraphicReselectPanel->Visible = false;
14283  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
14284  break;
14285 
14286  case DistanceContinuing:
14287  InfoPanel->Visible = true;
14288  if(ConstructPrefDir->PrefDirSize() == 1)
14289  {
14290  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
14291  }
14292  else
14293  {
14294  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
14295  }
14296  UserGraphicReselectPanel->Visible = false;
14297  ClearandRebuildRailway(54); // to remove earlier end marker if present
14298  break;
14299 
14300  case TrackSelecting:
14301  Track->CopyFlag = false;
14302  if(!SelectionValid)
14303  {
14304  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
14305  }
14306  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
14307  // ReselectMenuItemClick)
14308  InfoPanel->Visible = true;
14309  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
14310  SelectMenuItem->Enabled = false;
14311  ReselectMenuItem->Enabled = false;
14312  CancelSelectionMenuItem->Enabled = true;
14313  UserGraphicReselectPanel->Visible = false;
14314  break;
14315 
14316  case CopyMoving:
14317  Track->CopyFlag = true;
14318  InfoPanel->Visible = true;
14319  InfoPanel->Caption = "COPYING: Left click in selection && drag";
14320  CutMenuItem->Enabled = false;
14321  CopyMenuItem->Enabled = false;
14322  FlipMenuItem->Enabled = false;
14323  MirrorMenuItem->Enabled = false;
14324  RotRightMenuItem->Enabled = false;
14325  RotLeftMenuItem->Enabled = false;
14326  RotateMenuItem->Enabled = false;
14327  PasteMenuItem->Enabled = true;
14328 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying (dropped at 2.4.0 as all pastes are with attributes)
14329  DeleteMenuItem->Enabled = false;
14330  SelectLengthsMenuItem->Enabled = false;
14331  SelectBiDirPrefDirsMenuItem->Visible = false;
14332  CancelSelectionMenuItem->Enabled = true;
14336  UserGraphicReselectPanel->Visible = false;
14337  break;
14338 
14339  case CutMoving:
14340  {
14341  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14342  // erase track elements within selected region
14343  Track->CopyFlag = false;
14344  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
14345  ;
14346  int ErasedTrackVectorPosition;
14347  Screen->Cursor = TCursor(-11); // Hourglass;
14348  InfoPanel->Visible = true;
14349  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
14350  InfoPanel->Update();
14351  for(int H = SelectRect.left; H < SelectRect.right; H++)
14352  {
14353  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
14354  {
14355  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
14356  if(EraseSuccessfulFlag)
14357  {
14358  if(ErasedTrackVectorPosition > -1)
14359  {
14360  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
14361  }
14362  NeedToLink = true;
14363  }
14364  }
14365  }
14366  // erase text elements within selected region
14367  int LowSelectHPos = SelectRect.left * 16;
14368  int HighSelectHPos = SelectRect.right * 16;
14369  int LowSelectVPos = SelectRect.top * 16;
14370  int HighSelectVPos = SelectRect.bottom * 16;
14371  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
14372  {
14373  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
14374  TextPtr--) // reverse to prevent skipping during erase
14375  {
14376  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
14377  HighSelectVPos))
14378  {
14379  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
14380  {
14381  ;
14382  } // unused condition
14383 
14384  TextChangesMade = true;
14385  }
14386  }
14387  }
14388  // erase graphic elements that fall wholly within region to be overwritten
14389  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
14390  {
14391  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
14392  GraphicPtr--) // reverse to prevent skipping during erase
14393  {
14394  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
14395  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
14396  {
14397  Track->UserGraphicVector.erase(GraphicPtr);
14398  GraphicChangesMade = true;
14399  }
14400  }
14401  }
14402  Track->CheckMapAndTrack(11); // test
14403  Track->CheckMapAndInactiveTrack(10); // test
14404  Track->CheckLocationNameMultiMap(19); // test
14405  Screen->Cursor = TCursor(-2); // Arrow;
14406  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
14407  // if track not linked to begin with then becomes linked if NeedToLink false
14408  if(NeedToLink)
14409  {
14410  Track->SetTrackFinished(false); // corrected for v2.1.0
14411  }
14412  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
14413  CutMenuItem->Enabled = false;
14414  CopyMenuItem->Enabled = false;
14415  FlipMenuItem->Enabled = false;
14416  MirrorMenuItem->Enabled = false;
14417  RotRightMenuItem->Enabled = false;
14418  RotLeftMenuItem->Enabled = false;
14419  RotateMenuItem->Enabled = false;
14420  PasteMenuItem->Enabled = true;
14421 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting (dropped at 2.4.0 as all pastes are with attributes)
14422  DeleteMenuItem->Enabled = false;
14423  SelectLengthsMenuItem->Enabled = false;
14424  SelectBiDirPrefDirsMenuItem->Visible = false;
14425  CancelSelectionMenuItem->Enabled = true;
14428  if(NeedToLink || TextChangesMade || GraphicChangesMade)
14429  {
14430  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
14431  }
14432  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
14433  UserGraphicReselectPanel->Visible = false;
14435  } break;
14436 
14437  case Pasting:
14438  {
14439  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14440  int HDiff = SelectBitmapHLoc - SelectRect.left; // SelectBitmapHLoc/VLoc is the paste position & SelectRect.left/top is the original position
14441  int VDiff = SelectBitmapVLoc - SelectRect.top;
14442  if(!SelectionValid && !CancelSelectionFlag) // may be pasting into a new application so use clipboard, new at v2.8.0
14443  {
14444  bool ValidResult;
14445  RecoverClipboard(0, ValidResult); // new at v2.8.0
14446  if(ValidResult)
14447  {
14448  HDiff = Display->DisplayOffsetH - SelectRect.left; // SelectRect.left & top recovered in clipboard
14449  VDiff = Display->DisplayOffsetV - SelectRect.top;
14450  SelectBitmapHLoc = Display->DisplayOffsetH; // so the area to erase corresponds to the paste area (TLHC of screen = DisplayOffsetH & V)
14452  SelectionValid = false; // don't want reselect in new app after paste
14453  Track->SetTrackFinished(false); // would be set to false in other app but not in this so set it to false here
14455  {
14456  UnicodeString MessageStr =
14457  "Please be aware of the relevant conditions when pasting " "a railway segment from a different application.\n"
14458  "These are set out in section 3.5 of the manual and " "on-screen help under the heading 'Pasting in an application "
14459  "after cutting or copying from a different application'.\n\n" "This warning will not be shown again.\n\n" "Proceed?";
14460  int button = Application->MessageBox(MessageStr.c_str(), L"Warning", MB_YESNO | MB_ICONWARNING);
14462  if(button == IDNO)
14463  {
14464  CancelSelectionMenuItem->Click(); // reset clipboard etc
14465  Utilities->CallLogPop(2271);
14466  return;
14467  }
14468  }
14469  }
14470  else
14471  {
14472  Application->MessageBoxW(L"Unable to paste, clipboard does not contain a valid railway segment", L"Warning", MB_OK | MB_ICONWARNING);
14473  CancelSelectionMenuItem->Click(); // reset clipboard etc
14474  Utilities->CallLogPop(2272);
14475  return;
14476  }
14477  }
14478  if(CancelSelectionFlag) // plot cut area in original position in case moved
14479  {
14482  HDiff = 0;
14483  VDiff = 0;
14484  }
14485  Clipboard()->Clear(); // already cleared & closed if recovered clipboard but not otherwise so clear & close here
14486  Clipboard()->Close();
14489  bool NeedToLink = false;
14490  bool TrackLinkingRequiredFlag;
14491  Screen->Cursor = TCursor(-11); // Hourglass;
14492  InfoPanel->Visible = true;
14493  InfoPanel->Caption = "PASTING: Please wait";
14494  InfoPanel->Update();
14495 // erase track elements
14496  int LowSelectHLoc = SelectBitmapHLoc;
14497  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
14498  int LowSelectVLoc = SelectBitmapVLoc;
14499  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
14500  bool TrackEraseSuccessfulFlag; // needed but not used here
14501  int ErasedTrackVectorPosition;
14502 // new quick method of erasing, only need H & V values
14503  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
14504  {
14505  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
14506  {
14507  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
14508  if(ErasedTrackVectorPosition > -1)
14509  {
14510  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
14511  }
14512  }
14513  }
14514 
14515 // erase text elements that fall within region to be overwritten
14516  int LowSelectHPos = SelectBitmapHLoc * 16;
14517  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
14518  int LowSelectVPos = SelectBitmapVLoc * 16;
14519  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
14520  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
14521  {
14522  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
14523  TextPtr--) // reverse to prevent skipping during erase
14524  {
14525  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
14526  HighSelectVPos))
14527  {
14528  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
14529  {
14530  ;
14531  } // unused condition
14532 
14533  }
14534  }
14535  }
14536 // erase graphic elements that fall wholly within region to be overwritten
14537  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
14538  {
14539  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
14540  GraphicPtr--) // reverse to prevent skipping during erase
14541  {
14542  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
14543  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
14544  {
14545  Track->UserGraphicVector.erase(GraphicPtr);
14546  }
14547  }
14548  }
14549  // change the H & V values in SelectVector to the new positions in case Reselect chosen
14550  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
14551  {
14552  Track->SelectVectorAt(35, x).HLoc += HDiff;
14553  Track->SelectVectorAt(1, x).VLoc += VDiff;
14554  }
14555 
14556  // add the new track elements
14557  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
14558  {
14559  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
14560  {
14561  Track->SelectVectorAt(80, x).LocationName = "";
14563  }
14564  bool InternalChecks = false;
14565 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
14566 // {
14568  TrackLinkingRequiredFlag, InternalChecks);
14569  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
14570 // }
14571 /* drop this in v2.4.0 as all pastes are past with attributes
14572  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
14573  {
14574  int Aspect;
14575  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
14576  //this combination allows the funtion to distinguish between adding track and plotting with attributes
14577  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
14578  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
14579  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
14580  else Aspect = 4;
14581  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
14582  }
14583 */
14584  if(TrackLinkingRequiredFlag)
14585  {
14586  NeedToLink = true;
14587  }
14588  }
14589 
14590  // add the new text items
14591  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
14592  {
14593  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
14594  {
14595  TextPtr->HPos += HDiff * 16;
14596  TextPtr->VPos += VDiff * 16;
14597  AnsiString TempString = TextPtr->TextString;
14598  // have to create a new TextItem in order to create a new Font object
14599 /* drop in v2.4.0 as all pastes are paste with attributes
14600  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
14601  {
14602  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
14603  //use in PastingWithAttributes
14604  {
14605  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
14606  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
14607  }
14608  else TextPtr->TextString = ""; //delete the name for a simple paste
14609  }
14610 */
14611 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
14612 // {
14613  if(TextPtr->TextString.SubString(1, 4) == "##**")
14614  {
14615  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
14616  if(Track->CopyFlag)
14617  {
14618  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
14619  TempString = "";
14620  }
14621  }
14622  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
14624 // }
14625  }
14626  }
14627  // add new graphic items
14628  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
14629  {
14630  // keep contents of SelectVector valid in case reselect
14631  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
14632  GraphicPtr++)
14633  {
14634  GraphicPtr->HPos += HDiff * 16; // for reselect
14635  GraphicPtr->VPos += VDiff * 16; // for reselect
14636  Track->UserGraphicVector.push_back(*GraphicPtr);
14637  }
14638  }
14639  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
14640  Track->CopyFlag = false;
14641  Track->CheckMapAndTrack(7); // test
14642  Track->CheckMapAndInactiveTrack(7); // test
14643  Track->CheckLocationNameMultiMap(7); // test
14644  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
14645  // if track not linked to begin with then becomes linked if NeedToLink false
14646  if(NeedToLink)
14647  {
14648  Track->SetTrackFinished(false); // corrected for v2.1.0
14649  }
14650  Screen->Cursor = TCursor(-2); // Arrow;
14651  SetTrackBuildImages(14);
14653  // Level1Mode = TrackMode; //dropped as prevents AddTrack being called to display track elements
14654  // SetLevel1Mode(79);
14655  SetTrackModeEditMenu(5); // this is called from the above but is still needed to enable Select (& Reselect if pasted in same app) menu items
14656  PasteMenuItem->Enabled = false;
14657  UserGraphicReselectPanel->Visible = false;
14658  if(Level2TrackMode != AddTrack) // no need to set if already set in an earlier call
14659  {
14661  // No further recursion in AddTrack so OK
14662  SetLevel2TrackMode(42);
14663  }
14664  } break;
14665 
14666  case Deleting:
14667  {
14668  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14669  Track->CopyFlag = false;
14670  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
14671  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
14672  if(button == IDNO)
14673  {
14674  break;
14675  }
14676  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
14677  int ErasedTrackVectorPosition;
14678  Screen->Cursor = TCursor(-11); // Hourglass;
14679  InfoPanel->Visible = true;
14680  InfoPanel->Caption = "DELETING: Please wait";
14681  InfoPanel->Update();
14682  for(int H = SelectRect.left; H < SelectRect.right; H++)
14683  {
14684  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
14685  {
14686  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
14687  if(EraseSuccessfulFlag)
14688  {
14689  if(ErasedTrackVectorPosition > -1)
14690  {
14691  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
14692  }
14693  NeedToLink = true;
14694  }
14695  }
14696  }
14697  // erase text elements that fall within selected region
14698  int LowSelectHPos = SelectRect.left * 16;
14699  int HighSelectHPos = SelectRect.right * 16;
14700  int LowSelectVPos = SelectRect.top * 16;
14701  int HighSelectVPos = SelectRect.bottom * 16;
14702  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
14703  {
14704  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
14705  TextPtr--) // reverse to prevent skipping during erase
14706  {
14707  AnsiString Check = TextPtr->TextString;
14708  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
14709  HighSelectVPos))
14710  {
14711  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
14712  {
14713  ;
14714  } // unused condition
14715 
14716  TextChangesMade = true;
14717  }
14718  }
14719  }
14720  // erase graphic elements that fall within selected region
14721  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
14722  {
14723 
14724 // Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
14725 
14726 // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
14727 // GraphicPtr--) // reverse to prevent skipping during erase
14728 
14729 // i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
14730 // corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
14731 
14732  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
14733  GraphicPtr--) // reverse to prevent skipping during erase
14734  {
14735  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
14736  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
14737  {
14738  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
14739  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
14740  {
14741  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
14742  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
14743  (UserGraphicPtr->FileName == GraphicPtr->FileName))
14744  {
14745  Track->UserGraphicVector.erase(UserGraphicPtr);
14746  GraphicChangesMade = true;
14747  }
14748  }
14749  }
14750  }
14751  }
14752  // clear the selectvectors
14754  TextHandler->SelectTextVector.clear();
14755  Track->SelectGraphicVector.clear();
14756  Track->CheckMapAndTrack(10); // test
14757  Track->CheckMapAndInactiveTrack(9); // test
14758  Track->CheckLocationNameMultiMap(15); // test
14759  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
14760  // if track not linked to begin with then becomes linked if NeedToLink false
14761  if(NeedToLink)
14762  {
14763  Track->SetTrackFinished(false); // corrected for v2.1.0
14764  }
14765  if(NeedToLink || TextChangesMade || GraphicChangesMade)
14766  {
14767  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
14768  }
14769  Screen->Cursor = TCursor(-2); // Arrow;
14772  SetLevel1Mode(80);
14774  // No further recursion in AddTrack so OK
14775  UserGraphicReselectPanel->Visible = false;
14776  SetLevel2TrackMode(43);
14777  } break;
14778 
14779  default:
14780  // No further recursion in TrackMode so OK
14781  Track->CopyFlag = false;
14783  SetLevel1Mode(21);
14784  UserGraphicReselectPanel->Visible = false;
14785  break;
14786  }
14787  Utilities->CallLogPop(107);
14788 }
14789 
14790 // ---------------------------------------------------------------------------
14791 
14793 {
14794  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
14795  if(Level1Mode != PrefDirMode)
14796  {
14797  // No further recursion in BaseMode so OK
14798  Level1Mode = BaseMode;
14799  SetLevel1Mode(22);
14800  Utilities->CallLogPop(108);
14801  return;
14802  }
14804  {
14805  Utilities->CallLogPop(109);
14806  return;
14807  }
14808  switch(Level2PrefDirMode) // use the data member
14809  {
14810  case PrefDirContinuing:
14811  {
14812  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14813  InfoPanel->Visible = true;
14814  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
14815  {
14816  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
14817  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
14818  }
14819  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
14820  DeleteOnePrefDirButton->Enabled = false;
14821  bool LeadingPointsAtLastElement = false;
14822  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
14823  {
14824  if(LeadingPointsAtLastElement) // size must be > 1
14825  {
14826  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
14827  DeleteOnePrefDirButton->Enabled = true;
14828  }
14829  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
14830  {
14831  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
14832  }
14833  }
14834  else // size > 1 & EndPossible
14835  {
14836  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
14837  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
14838  {
14839  AddPrefDirButton->Enabled = true;
14840  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
14841  }
14842  DeleteOnePrefDirButton->Enabled = true;
14843  }
14844  ExitPrefDirButton->Enabled = true;
14845  ClearandRebuildRailway(40); // to show truncated PrefDirs
14846  } break;
14847 
14848  case PrefDirSelecting:
14849  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
14850  InfoPanel->Visible = true;
14851  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
14852  SelectMenuItem->Enabled = false;
14853  ReselectMenuItem->Enabled = false;
14854  CancelSelectionMenuItem->Enabled = true;
14855  break;
14856 
14857  default:
14858  // No further recursion in PrefDirMode so OK
14860  SetLevel1Mode(23);
14861  break;
14862  }
14863  Utilities->CallLogPop(110);
14864 }
14865 
14866 // ---------------------------------------------------------------------------
14867 
14869 {
14870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
14871  if(Level1Mode != OperMode)
14872  {
14873  // No further recursion in BaseMode so OK
14874  Level1Mode = BaseMode;
14875  SetLevel1Mode(24);
14876  Utilities->CallLogPop(111);
14877  return;
14878  }
14879  if(Level2OperMode == NoOperMode)
14880  {
14881  Utilities->CallLogPop(112);
14882  return;
14883  }
14884  CallingOnButton->Visible = true;
14885  PresetAutoSigRoutesButton->Visible = false;
14886  switch(Level2OperMode) // use the data member
14887  {
14888  case Operating:
14889  {
14890  // have to use braces as otherwise the default case bypasses the initialisation of local variables
14891  OperateButton->Enabled = true;
14892  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
14893  ExitOperationButton->Enabled = true;
14894  TTClockAdjButton->Enabled = false;
14895  if(TTClockSpeed == 2)
14896  {
14897  TTClockSpeedLabel->Caption = "x2";
14898  }
14899  else if(TTClockSpeed == 4)
14900  {
14901  TTClockSpeedLabel->Caption = "x4";
14902  }
14903  else if(TTClockSpeed == 8)
14904  {
14905  TTClockSpeedLabel->Caption = "x8";
14906  }
14907  else if(TTClockSpeed == 16)
14908  {
14909  TTClockSpeedLabel->Caption = "x16";
14910  }
14911  else if(TTClockSpeed == 0.5)
14912  {
14913  TTClockSpeedLabel->Caption = "x1/2";
14914  }
14915  else if(TTClockSpeed == 0.25)
14916  {
14917  TTClockSpeedLabel->Caption = "x1/4";
14918  }
14919  else if(TTClockSpeed == 0.125)
14920  {
14921  TTClockSpeedLabel->Caption = "x1/8";
14922  }
14923  else if(TTClockSpeed == 0.0625)
14924  {
14925  TTClockSpeedLabel->Caption = "x1/16";
14926  }
14927  else
14928  {
14929  TTClockSpeed = 1;
14930  TTClockSpeedLabel->Caption = "x1";
14931  }
14932  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
14934  {
14935  // send message to performance log
14936  if(TTClockSpeed == 2)
14937  {
14938  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
14939  }
14940  else if(TTClockSpeed == 4)
14941  {
14942  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
14943  }
14944  else if(TTClockSpeed == 8)
14945  {
14946  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
14947  }
14948  else if(TTClockSpeed == 16)
14949  {
14950  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
14951  }
14952  else if(TTClockSpeed == 0.5)
14953  {
14954  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
14955  }
14956  else if(TTClockSpeed == 0.25)
14957  {
14958  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
14959  }
14960  else if(TTClockSpeed == 0.125)
14961  {
14962  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
14963  }
14964  else if(TTClockSpeed == 0.0625)
14965  {
14966  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
14967  }
14968  else
14969  {
14970  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
14971  }
14972  }
14973  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
14974  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
14975  {
14976  // send message to performance log
14977  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
14978  int HoursIncrease = 0;
14979  while(MinsIncrease >= 60)
14980  {
14981  HoursIncrease++;
14982  MinsIncrease -= 60;
14983  }
14984  if(HoursIncrease == 0)
14985  {
14986  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
14987  }
14988  else if(MinsIncrease == 0)
14989  {
14990  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
14991  }
14992  else
14993  {
14994  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
14995  }
14996  Display->PerformanceLog(13, TimeMessage);
14997  }
14998  WarningHover = false;
15001  {
15002  MTBFEditBox->Visible = true;
15003  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
15004  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
15005  MTBFLabel->Visible = true;
15006  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15008  }
15009  else
15010  {
15011  MTBFEditBox->Visible = false;
15012  MTBFEditBox->Text = "";
15013  MTBFLabel->Visible = false;
15014  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15016  }
15017  TrainController->BaseTime = TDateTime::CurrentDateTime();
15018 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
15019  } break;
15020 
15021  case Paused:
15022  OperateButton->Enabled = true;
15023  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
15024  ExitOperationButton->Enabled = true;
15025  TTClockAdjButton->Enabled = true;
15030 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
15033  break;
15034 
15035  // don't need a separate case for PreStart
15036 
15037  default:
15038  // No further recursion in OperMode so OK
15039  Level1Mode = OperMode;
15040  SetLevel1Mode(25);
15041  break;
15042  }
15043  Utilities->CallLogPop(113);
15044 }
15045 
15046 // ---------------------------------------------------------------------------
15047 
15048 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
15049 {
15050  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
15051  float LockDelay = 120.0;
15052 
15053  if(!AllRoutes->LockedRouteVector.empty())
15054  {
15055  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
15056  {
15057  bool BreakFlag = false;
15058  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
15059  {
15060  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
15061  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
15062  {
15063  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
15064  AnsiString(LRVIT->LastTrackVectorPosition));
15065  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
15066  {
15067  // examine the element one earlier in the route than the last
15068  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
15069  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
15070  {
15071  BreakFlag = true;
15072  }
15073  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
15074  if(BreakFlag)
15075  {
15076  break; // train removed earlier element from route so stop here
15077  }
15078  }
15079  if(!BreakFlag)
15080  {
15081  // still need to remove the element at the TruncateTrackVectorPosition
15082  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
15083  {
15084  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
15085  Route.LastElementPtr(20)->GetELink());
15086  }
15087  }
15088  AllRoutes->CheckMapAndRoutes(10); // test
15089  AllRoutes->LockedRouteVector.erase(LRVIT);
15090  if(!Display->ZoomOutFlag)
15091  {
15092  ClearandRebuildRailway(17); // to get rid of route graphics
15093  }
15095  }
15096  }
15097  else
15098  {
15099  AllRoutes->LockedRouteVector.erase(LRVIT);
15100  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
15101  // hence no longer needed so get rid of it
15102  }
15103  }
15104  }
15105  Utilities->CallLogPop(743);
15106 }
15107 
15108 // ---------------------------------------------------------------------------
15109 
15110 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
15111 {
15112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
15114  {
15116  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
15117  AutoSigVectorIT--)
15118  {
15119  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
15120  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
15121  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
15122  TPrefDirElement TempPrefDirElement;
15123  int TempLockedVectorNumber;
15124  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
15125  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
15126  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
15127  // route exiting at a continuation
15128  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
15129  {
15130  continue;
15131  }
15132  // end of additions
15133  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
15134  {
15135  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
15136  AutoSigVectorIT->AccessNumber++;
15137  continue;
15138  }
15139  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
15140  {
15141  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
15142  AutoSigVectorIT->AccessNumber++;
15143  continue;
15144  }
15145  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
15146  {
15147  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
15148  AutoSigVectorIT->AccessNumber++;
15149  continue;
15150  }
15151  }
15152  // examine all vector for any expired values & erase
15153  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
15154  AutoSigVectorIT--)
15155  {
15156  if(AutoSigVectorIT->AccessNumber > 2)
15157  {
15158  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
15159  }
15160  }
15161  }
15162  Utilities->CallLogPop(744);
15163 }
15164 
15165 // ---------------------------------------------------------------------------
15166 
15168 {
15169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
15170  TPoint MousePoint = Mouse->CursorPos;
15171  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
15172  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
15173 
15174  if(!OAListBoxRightMouseButtonDown && ((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0)))
15175  {
15176  // added !OAListBoxRightMouseButtonDown at v2.7.0 so can still obtain info & move to trains from OAListBox even if they are out of the main screen area
15177  FloatingPanel->Visible = false;
15178  Utilities->CallLogPop(1432);
15179  return;
15180  }
15181  if(PerformancePanel->Visible)
15182  {
15183  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
15184  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
15185  (PerformancePanel->Top + PerformancePanel->Height)))
15186  {
15187  // dont show floating window if mouse over performance panel
15188  FloatingPanel->Visible = false;
15189  Utilities->CallLogPop(1715);
15190  return;
15191  }
15192  }
15193  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
15194  {
15195  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
15196  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
15197  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
15198  {
15199  // dont show floating window if mouse over TimetableEditPanel
15200  FloatingPanel->Visible = false;
15201  Utilities->CallLogPop(2240);
15202  return;
15203  }
15204  }
15205  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
15206  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
15207  int HLoc, VLoc;
15208 
15209  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
15210 
15211  if(Display->ZoomOutFlag)
15212  {
15213  Utilities->CallLogPop(1123);
15214  return;
15215  }
15216  bool MouseOverOAPanel = false;
15217 // this flag added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
15218  if(OperatorActionPanel->Visible)
15219  {
15220  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
15221  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
15222  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
15223  {
15224  MouseOverOAPanel = true;
15225  }
15226  }
15227  if((TrackInfoOnOffMenuItem->Caption == "Hide") && !MouseOverOAPanel)
15228  // MouseOverOAPanel condit added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
15229  {
15230  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
15231  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
15232  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
15233  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
15234  AnsiString SigAspectString = ""; // new at version 0.6
15235  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
15236  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
15237  TTrackElement ActiveTrackElement, InactiveTrackElement;
15238  if(InactiveTrackFoundFlag)
15239  {
15240  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
15241  IATrackSN = InactiveTrackElement.LocationName;
15242  }
15243  if(ActiveTrackFoundFlag)
15244  {
15245  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
15246  ATrackSN = ActiveTrackElement.LocationName;
15247  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
15248  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
15249  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
15250  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
15251  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
15252  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
15253  {
15254  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
15255  }
15256  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
15257  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
15258  {
15259  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
15260  }
15261  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
15262  {
15263  TwoTrack = true;
15264  }
15265  Length01Str = AnsiString(ActiveTrackElement.Length01);
15266  if(Length01Str == "-1")
15267  {
15268  Length01Str = "Not Set";
15269  }
15270  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
15271  if(SpeedLimit01Str == "-1")
15272  {
15273  SpeedLimit01Str = "Not Set";
15274  }
15275  if(TwoTrack)
15276  {
15277  Length23Str = AnsiString(ActiveTrackElement.Length23);
15278  if(Length23Str == "-1")
15279  {
15280  Length23Str = "Not Set"; // shouldn't be -1 but leave in
15281  }
15282  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
15283  if(SpeedLimit23Str == "-1")
15284  {
15285  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
15286  }
15287  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
15288  {
15289  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
15290  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
15291  }
15292  else if(ActiveTrackElement.TrackType == Points)
15293  {
15294  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
15295  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
15296  SpeedLimit23Str + " km/h";
15297  }
15298  else if(ActiveTrackElement.TrackType == Crossover)
15299  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
15300  {
15301  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
15302  {
15303  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
15304  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
15305  }
15306  else if(ActiveTrackElement.SpeedTag == 47)
15307  {
15308  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
15309  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
15310  }
15311  else if(ActiveTrackElement.SpeedTag == 45)
15312  {
15313  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
15314  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
15315  }
15316  else if(ActiveTrackElement.SpeedTag == 44)
15317  {
15318  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
15319  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
15320  }
15321  else if(ActiveTrackElement.SpeedTag == 16)
15322  {
15323  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
15324  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
15325  SpeedLimit23Str + " km/h";
15326  }
15327  }
15328  else // bridge
15329  {
15330  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
15331  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
15332  }
15333  }
15334  else
15335  {
15336  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
15337  }
15338  }
15339  if(ActiveTrackFoundFlag)
15340  {
15341  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
15342  // in case wish to resurrect this line for any reason
15343  ShowTrackFloatFlag = true;
15344  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
15345  {
15346  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
15347  }
15348  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
15349  {
15350  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
15351  }
15352 
15353  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
15354  {
15355  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
15356  }
15357 
15358  else // no timetable or location name, just track
15359  {
15360  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
15361  }
15362  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
15363  {
15364  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
15365  {
15366  SigAspectString = "\nThree-aspect signal";
15367  }
15368  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
15369  {
15370  SigAspectString = "\nTwo-aspect signal";
15371  }
15372  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
15373  {
15374  SigAspectString = "\nGround signal";
15375  }
15376  else
15377  {
15378  SigAspectString = "\nFour-aspect signal";
15379  }
15380  TrackFloat += SigAspectString;
15381  }
15382  } // if(ActiveFoundFlag)
15383  else if(InactiveTrackFoundFlag) // inactive element but no active element,
15384  // i.e. concourse or non-station name at a blank element
15385  {
15386  ShowTrackFloatFlag = true;
15387  if(InactiveTrackElement.TrackType != Parapet)
15388  {
15389  if(IATrackSN == "")
15390  {
15391  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
15392  }
15393  else
15394  {
15395  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
15396  }
15397  }
15398  else // it is a parapet, just show the ID
15399  {
15400  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
15401  }
15402  }
15403  }
15404 // end of TrackFloat section
15405 
15406  bool OAListBoxFloatRequired = false; // identifies which window needs the float
15407  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
15408  // if caption is 'Hide' label is required
15409  {
15410  bool FoundFlag;
15411  AnsiString FormatOneDPStr = "####0.0";
15412  AnsiString FormatNoDPStr = "#######0";
15413 // AnsiString Format5DPStr = "####0.00000"; //temporary
15414  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
15415  AnsiString SpecialStr = "";
15416  if(OperatorActionPanel->Visible) // added after v2.6.1 to show floating window for trains in actions due list
15417  {
15418  if(OAListBox->MouseInClient && !OperatorActionPanel->MouseInClient && OAListBoxRightMouseButtonDown)
15419  {
15420  int X = OAListBox->ScreenToClient(MousePoint).x;
15421  int Y = OAListBox->ScreenToClient(MousePoint).y;
15422  int TrainID = -1, ContinuationPos = -1;
15423  if(GetTrainIDOrContinuationPosition(1, X, Y, TrainID, ContinuationPos))
15424  {
15425  OAListBoxFloatRequired = true;
15426  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
15427  {
15428  ShowTrainStatusFloatFlag = true;
15429  }
15430  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
15431  {
15432  ShowTrainTTFloatFlag = true;
15433  }
15434  if((TrainID > -1) && (ShowTrainStatusFloatFlag || ShowTrainTTFloatFlag))
15435  {
15436  TTrain Train = TrainController->TrainVectorAtIdent(53, TrainID);
15437  TrainStatusFloat = GetTrainStatusFloat(0, TrainID, FormatNoDPStr, SpecialStr);
15438  TrainTTFloat = Train.FloatingTimetableString(1, Train.ActionVectorEntryPtr);
15439  }
15440  else if(ContinuationPos > -1)
15441  {
15442  GetTrainFloatingInfoFromContinuation(0, ContinuationPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
15443  }
15444  }
15445  }
15446  }
15447  if(!OAListBoxFloatRequired) // condition added after v2.6.1 so only one floating window can show
15448  {
15449  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
15450  if(FoundFlag && !MouseOverOAPanel) // MouseOverOAPanel added at v2.7.0 to prevent trains showimng behind OA panel
15451  {
15452  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
15453  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
15454  {
15455  int TrainID = Track->TrackElementAt(452, VecPos).TrainIDOnElement;
15456  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
15457  {
15458  ShowTrainStatusFloatFlag = true;
15459  TrainStatusFloat = GetTrainStatusFloat(1, TrainID, FormatNoDPStr, SpecialStr);
15460  }
15461  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
15462  {
15463  ShowTrainTTFloatFlag = true;
15464  TTrain Train = TrainController->TrainVectorAtIdent(54, TrainID);
15465  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
15466  }
15467  }
15468 
15469  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
15470  // always give train information if a train present, but if not & either of train status or timetable info
15471  // selected then give next expected train to enter, or 'No trains expected'
15472  {
15473  TrainStatusFloat = "No trains expected";
15474  TrainTTFloat = "No timetable";
15475  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
15476  {
15477  ShowTrainStatusFloatFlag = true;
15478  }
15479  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
15480  {
15481  ShowTrainTTFloatFlag = true;
15482  }
15484  {
15485  GetTrainFloatingInfoFromContinuation(1, VecPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
15486  }
15487  }
15488  }
15489  }
15490  }
15491 // end of TrainFloat section
15492  AnsiString Caption;
15493 
15494  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
15495  {
15496  FloatingPanel->Visible = false;
15497  Utilities->CallLogPop(1485);
15498  return; // return with label invisible
15499  }
15500  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
15501  {
15502  Caption = TrackFloat;
15503  }
15504  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
15505  {
15506  Caption = TrainStatusFloat;
15507  }
15508  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
15509  {
15510  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
15511  }
15512  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
15513  {
15514  if(TrainStatusFloat == "No trains expected")
15515  {
15516  Caption = TrainStatusFloat;
15517  }
15518  else
15519  {
15520  Caption = TrainTTFloat;
15521  }
15522  }
15523  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
15524  {
15525  if(TrainStatusFloat == "No trains expected")
15526  {
15527  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
15528  }
15529  else
15530  {
15531  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
15532  }
15533  }
15534  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
15535  {
15536  if(TrainStatusFloat == "No trains expected")
15537  {
15538  Caption = TrainStatusFloat;
15539  }
15540  else
15541  {
15542  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
15543  }
15544  }
15545  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
15546  {
15547  if(TrainStatusFloat == "No trains expected")
15548  {
15549  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
15550  }
15551  else
15552  {
15553  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
15554  }
15555  }
15556  int WindowOffsetLeft = 16;
15557  int WindowOffsetRight = 16;
15558  if(OAListBoxFloatRequired)
15559  {
15560  WindowOffsetLeft = 32;
15561  WindowOffsetRight = 64;
15562  }
15563  FloatingLabel->Caption = Caption; // set this here so dimensions correct in calculations, moved from below at v2.7.0
15564  FloatingPanel->Visible = true; // need this or dimensions still not valid, moved from below at v2.7.0
15565 
15566  int Left = ScreenX + MainScreen->Left + WindowOffsetRight; // so lhs of window is WindowOffset to the right of the mouse pos
15567 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
15568 // offset 32 to the right and 95 down from the interface form
15569  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
15570  {
15571  Left = ScreenX - FloatingPanel->Width + 32 - WindowOffsetLeft;
15572  }
15573 // so rhs of window is 32 - WindowOffset to the left of the mouse pos (+32 would be at mouse pos)
15574  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
15575 
15576  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
15577  {
15578  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
15579  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
15580  // lose something then it's best to be from the bottom
15581  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
15582  // obscure the window
15583  {
15584  Top = 30;
15585  }
15586  }
15587 /* if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top)) //dropped at v2.7.0 as causes more flickler than allowing window to move with mouse
15588  {
15589  FloatingPanel->Visible = false; // so doesn't flicker when reposition
15590  FloatingPanel->Left = Left;
15591  FloatingPanel->Top = Top;
15592  Utilities->CallLogPop(1917);
15593  return;
15594  }
15595 */
15596 
15597  FloatingPanel->Left = Left; // new at v2.7.0 in place of above
15598  FloatingPanel->Top = Top;
15599 
15600 // FloatingLabel->Caption = Caption; moved up at v2.7.0
15601 // FloatingPanel->Visible = true; // moved up at v2.7.0
15602  FloatingPanel->BringToFront();
15603  Utilities->CallLogPop(746);
15604 }
15605 
15606 // ---------------------------------------------------------------------------
15607 
15608 void TInterface::GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat,
15609  AnsiString &TrainTTFloat)
15610 {
15611  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainFloatingInfoFromContinuation");
15613  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
15614  float EntrySpeed;
15616  {
15617  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
15618  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
15619  {
15620  CTEIt++;
15621  }
15623  {
15624  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
15625  AnsiString ServiceReferenceInfo = "";
15626  // Repeat information
15627  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
15628  {
15629  if(CTEIt->second.RepeatNumber == 0)
15630  {
15631  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
15632  {
15633  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
15634  }
15635  else
15636  {
15637  ServiceReferenceInfo = "\nFirst service";
15638  }
15639  }
15640  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
15641  {
15642  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
15643  }
15644  else
15645  {
15646  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " + TTDEPtr->ServiceReference;
15647  }
15648  }
15649  else
15650  {
15651  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
15652  {
15653  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
15654  }
15655  }
15656  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
15657  {
15658  SpecialStr = "\nTrain under signaller control";
15659  EntrySpeed = TTDEPtr->SignallerSpeed;
15660  if(EntrySpeed > LineSpeedLimit)
15661  {
15662  EntrySpeed = LineSpeedLimit;
15663  }
15664  }
15665  else
15666  {
15667  EntrySpeed = TTDEPtr->StartSpeed;
15668  if(EntrySpeed > LineSpeedLimit)
15669  {
15670  EntrySpeed = LineSpeedLimit;
15671  }
15672  }
15673  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
15674  {
15675  TDateTime TempTime = CTEIt->first;
15676 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
15677  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
15678  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " + Utilities->Format96HHMM(TempTime);
15679  }
15680  else
15681  {
15682  TDateTime TempTime = CTEIt->first;
15683 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
15684  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
15685  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " + Utilities->Format96HHMM(TempTime);
15686  }
15687  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
15688  {
15689  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
15690  {
15691  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber, CTEIt->second.IncrementalMinutes,
15692  CTEIt->second.IncrementalDigits);
15693  }
15694  }
15695  }
15696  }
15697  Utilities->CallLogPop(2262);
15698 }
15699 
15700 // ---------------------------------------------------------------------------
15701 
15702 AnsiString TInterface::GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
15703 // new after v2.6.1 to make it easier to show also from actions due panel
15704 {
15705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainStatusFloat");
15706  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
15707  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
15708  AnsiString FormatOneDPStr = "####0.0", MaxBrakeStr = "", MaxSpeedStr = "", TrainStatusFloat;
15709 
15710  double CurrSpeed;
15711  TTrain Train = TrainController->TrainVectorAtIdent(1, TrainID);
15712  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
15713  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
15714  if(Train.BeingCalledOn)
15715  {
15716  MaxSpeedStr = "30";
15717  }
15718  else
15719  {
15720  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
15721  }
15722  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
15723  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
15724  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
15725  TDateTime TimeLeft;
15726  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
15727  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
15728  HeadCode = Train.HeadCode;
15729  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
15730  {
15731  if(Train.RepeatNumber == 0)
15732  {
15733  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
15734  {
15735  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
15736  }
15737  else
15738  {
15739  ServiceReferenceInfo = "\nFirst service";
15740  }
15741  }
15742  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
15743  {
15744  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
15745  }
15746  else
15747  {
15748  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " + Train.TrainDataEntryPtr->ServiceReference;
15749  }
15750  }
15751  else
15752  {
15753  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
15754  {
15755  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
15756  }
15757  }
15758  if(Train.Stopped())
15759  {
15760  if(Train.SignallerStopped)
15761  {
15762  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
15763  }
15764  if(Train.NotInService)
15765  {
15766  Status = "Not in service"; // not used so far but leave it in
15767  }
15768  if(Train.StoppedAtBuffers)
15769  {
15770  Status = "Stopped at buffers";
15771  }
15772  if(Train.StoppedAtSignal)
15773  {
15774  Status = "Stopped at signal";
15775  }
15776  if(Train.StoppedForTrainInFront)
15777  {
15778  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
15779  }
15780  if(Train.StoppedAtLocation)
15781  {
15782  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
15783  }
15784  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
15785  {
15786  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
15787  }
15788  if(Train.StoppedWithoutPower)
15789  {
15790  if(Train.TrainFailed)
15791  {
15792  Status = "Stopped without power - train failed";
15793  }
15794  else
15795  {
15796  Status = "Stopped without power";
15797  }
15798  }
15799  if(Train.StoppedAfterSPAD)
15800  {
15801  Status = "Stopped - signal passed at danger";
15802  }
15803  if(Train.Derailed)
15804  {
15805  Status = "Derailed";
15806  }
15807  if(Train.Crashed)
15808  {
15809  Status = "Crashed";
15810  }
15811  CurrSpeed = 0;
15812  }
15813  else if(Train.OneLengthAccelDecel)
15814  {
15815  if(Train.FirstHalfMove)
15816  {
15817  Status = "Accelerating"; // just display a linear speed rise over half length
15818  BrakePCRate = 0; // reset to proper value during braking
15819  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
15820  }
15821  else
15822  {
15823  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
15824  if(BrakePCRate < 55)
15825  {
15826  Status = "Light braking";
15827  }
15828  else if(BrakePCRate < 90)
15829  {
15830  Status = "Heavy braking";
15831  }
15832  else
15833  {
15834  Status = "Emergency braking";
15835  }
15836  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
15837  }
15838  }
15839  else if(Train.BrakeRate > 0.01)
15840  {
15841  if(BrakePCRate < 55)
15842  {
15843  Status = "Light braking";
15844  }
15845  else if(BrakePCRate < 90)
15846  {
15847  Status = "Heavy braking";
15848  }
15849  else
15850  {
15851  Status = "Emergency braking";
15852  }
15853  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
15854  }
15855 
15856  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
15857  {
15858  Status = "Accelerating"; // just display a linear speed rise over half length
15859  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
15860  }
15861 
15862  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
15863  {
15864  Status = "Accelerating";
15865  CurrSpeed = Train.ExitSpeedHalf +
15866  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
15867  }
15868 
15869  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
15870  {
15871  if(Train.PowerAtRail < 1)
15872  {
15873  if(Train.TrainFailed)
15874  {
15875  Status = "Coasting - train failed";
15876  }
15877  else
15878  {
15879  Status = "Coasting - no power";
15880  }
15881  CurrSpeed = Train.ExitSpeedFull;
15882  }
15883  else
15884  {
15885  Status = "Constant speed";
15886  CurrSpeed = Train.ExitSpeedFull;
15887  }
15888  }
15889 
15890  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
15891  {
15892  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
15893  {
15894  if(Train.TrainFailed)
15895  {
15896  Status = "Coasting - train failed";
15897  }
15898  else
15899  {
15900  Status = "Coasting - no power";
15901  }
15902  CurrSpeed = Train.ExitSpeedHalf;
15903  }
15904  else
15905  {
15906  Status = "Constant speed";
15907  CurrSpeed = Train.ExitSpeedHalf;
15908  }
15909  }
15910  if(Train.TimetableFinished)
15911  {
15912  if(Train.TrainMode == Signaller)
15913  {
15914  NextStopStr = "At signaller's discretion";
15915  }
15916  else
15917  {
15918  NextStopStr = "None";
15919  }
15920  }
15921  else
15922  {
15923  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
15924  }
15925  if(Train.TrainMode == Signaller)
15926  {
15927  SpecialStr = "Train under signaller control" + AnsiString('\n');
15928  }
15929  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
15930  {
15931  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
15932  }
15933  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
15934  if(RemTimeHalf < 0)
15935  {
15936  RemTimeHalf = 0;
15937  }
15938  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
15939  if(RemTimeFull < 0)
15940  {
15941  RemTimeFull = 0;
15942  }
15943  if(RemTimeHalf > 0)
15944  {
15945  TimeLeft = RemTimeHalf;
15946  }
15947  else
15948  {
15949  TimeLeft = RemTimeFull;
15950  }
15951  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
15952  if(Train.Stopped())
15953  {
15954  TimeToNextMovementStr = "";
15955  }
15956  if(Train.Stopped())
15957  {
15958  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
15959  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' + "Next: " +
15960  NextStopStr;
15961  }
15962  else
15963  {
15964  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
15965  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + ": " +
15966  CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
15967  }
15968  Utilities->CallLogPop(2263);
15969  return(TrainStatusFloat);
15970 }
15971 
15972 // ---------------------------------------------------------------------------
15973 
15974 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
15975 // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
15976 // Gap flashing is cancelled on any mousedown event
15977 
15978 // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
15979 {
15980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
15982  {
15983  if(WarningFlash)
15984  {
15985  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
15987  }
15988  else
15989  {
15990  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
15992  }
15993  }
15995  {
15996  if(WarningFlash)
15997  {
16002  Display->Update();
16003  }
16004  else
16005  {
16010  Display->Update();
16011  }
16012  }
16013 // deal with gap setting - added at v2.6.1 to make location easier
16015  {
16017  }
16019  {
16020  Display->Ellipse(2, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB0G0R5);
16021  }
16023  {
16025  }
16027  {
16028  Display->Ellipse(3, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB5G5R5);
16029  }
16030 // deal with other flashing graphics
16032  {
16033  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
16034  {
16035  // cancel if train is moving & arrives on any part of flashing route
16037  {
16038  Track->RouteFlashFlag = false;
16040  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
16041  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
16042  Utilities->CallLogPop(75);
16043  return;
16044  }
16045  InfoPanel->Visible = true;
16046  if(Level2OperMode == PreStart)
16047  {
16048  InfoPanel->Caption = "PRE-START: Route setting in progress";
16049  }
16050  else
16051  {
16052  InfoPanel->Caption = "OPERATING: Route setting in progress";
16053  }
16054  if(WarningFlash)
16055  {
16057  }
16058  else
16059  {
16061  }
16062  }
16063  else
16064  {
16065 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
16066 // stop clock while converting route as can take several seconds
16067  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
16069  if(PreferredRouteFlag)
16070  {
16072  }
16073  else
16074  {
16076  }
16077  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
16078  TrainController->BaseTime = TDateTime::CurrentDateTime();
16080  Track->RouteFlashFlag = false;
16082  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
16083  }
16084  }
16085  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
16086  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
16087  // no need to call Clearand... as that is called when revert to normal mode
16088  {
16089  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
16090  {
16091  Track->RouteFlashFlag = false;
16092  if(PreferredRouteFlag)
16093  {
16095  }
16096  else
16097  {
16099  }
16100  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
16101  }
16102  }
16104  {
16105  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
16106  {
16107  // cancel if train is present on or enters a flashing point, either selected or diverging
16109  {
16111  Track->PointFlashFlag = false;
16113  Utilities->CallLogPop(76);
16114  return;
16115  }
16117  {
16119  Track->PointFlashFlag = false;
16121  Utilities->CallLogPop(77);
16122  return;
16123  }
16124  if(WarningFlash)
16125  {
16128  }
16129  else
16130  {
16132  }
16133  }
16134  else
16135  {
16140  {
16144  }
16146  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
16147  Track->PointFlashFlag = false;
16149  }
16150  }
16152  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
16153  {
16154  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
16155  {
16159  {
16162  }
16163  Track->PointFlashFlag = false;
16165  }
16166  }
16167 // deal with level crossings
16168  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
16169  {
16170  int H;
16171  int V;
16172 
16173  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
16174  {
16175  bool Manual = false;
16176  if(Track->ChangingLCVector.at(x).TypeOfRoute == 2) // manual
16177  {
16178  Manual = true;
16179  }
16180  H = Track->ChangingLCVector.at(x).HLoc;
16181  V = Track->ChangingLCVector.at(x).VLoc;
16182  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
16183  // still flashing
16184  {
16185  if(WarningFlash)
16186  {
16187  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
16188  {
16189  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
16190 // always plots red when raising
16191  }
16192  else
16193  {
16194  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
16195  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
16196  }
16197  }
16198  else
16199  {
16200  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
16201  Track->ChangingLCVector.at(x).TypeOfRoute, Display);
16202  }
16203  }
16204  else
16205  // flashing period finished
16206  {
16207  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
16208  {
16209  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
16210 // always plot red when fully raised
16211  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
16212  // attributes set to 2 when changing state, now reset to 0, no other actions needed
16213  }
16214  else
16215  // barriers lowering
16216  {
16217  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
16218  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
16219  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
16220  bool FoundFlag;
16221  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
16222  if(!FoundFlag)
16223  {
16224  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
16225  }
16226  int RouteNumber;
16227  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
16228  // don't need returned value of RouteType
16229  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
16230  {
16231  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
16232  }
16233  }
16234  }
16235  }
16236  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
16237  {
16238  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector if lowering, reset the start timer (to time the barrier down period)
16239  // and for either raising or lowering erase the object from the ChangingLCVector
16240  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
16241  {
16242  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
16243  {
16244  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
16245  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
16246  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
16247  }
16248  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
16249  }
16250  }
16251  }
16252  Utilities->CallLogPop(747);
16253 }
16254 
16255 // ---------------------------------------------------------------------------
16256 
16258 // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
16259 {
16260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
16261 
16262 // set save railway buttons
16263  bool SaveRailwayButtonsFlag = true;
16264 
16265  SaveRailwayTBPButton->Visible = true;
16266  SaveRailwayPDPButton->Visible = true;
16267  SaveSessionButton->Visible = true;
16268  if(Level1Mode == OperMode)
16269  {
16271  {
16272  SaveRailwayButtonsFlag = false;
16273  }
16274  // set PresetAutoSigRoutesButton enabled or not
16275  // enable if PreStart & no routes set
16276  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
16277  {
16278  PresetAutoSigRoutesButton->Enabled = true;
16279  }
16280  else
16281  {
16282  PresetAutoSigRoutesButton->Enabled = false;
16283  }
16284  }
16285  else
16286  {
16288  && Track->UserGraphicVector.empty()))
16289  {
16290  SaveRailwayButtonsFlag = false;
16291  }
16292  else if(SavedFileName != "")
16293  {
16294  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
16295  {
16296  if(!(Track->IsReadyForOperation(false)))
16297  {
16298  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
16299  }
16300  }
16301  }
16302  }
16303  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
16304  {
16305  SaveRailwayBaseModeButton->Visible = true;
16306  }
16307  else
16308  {
16309  SaveRailwayBaseModeButton->Visible = false;
16310  }
16311  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
16312  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
16313  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
16314  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
16315 
16316 // set formatted timetable menu item
16317  if(TimetableTitle == "")
16318  {
16319  ExportTTMenuItem->Enabled = false;
16320  }
16321  else
16322  {
16323  ExportTTMenuItem->Enabled = true;
16324  }
16325 // set info menu items
16327  {
16328  FloatingInfoMenu->Enabled = false;
16329  TrackInfoMenuItem->Enabled = false;
16330  TrainInfoMenuItem->Enabled = false;
16331  }
16332  else
16333  {
16334  FloatingInfoMenu->Enabled = true;
16335  TrackInfoMenuItem->Enabled = true;
16336  if(Level1Mode == OperMode)
16337  {
16338  TrainInfoMenuItem->Enabled = true;
16339  }
16340  else
16341  {
16342  TrainInfoMenuItem->Enabled = false;
16343  }
16344  }
16345 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
16346 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
16347 // there has been a legitimate change of state since the last access
16348 
16349  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
16350  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
16351 
16352  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
16353  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
16354  AnsiString OperatingPanelLabelCaptionStr = "Operation";
16355  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
16356 
16357  if(!Display->ZoomOutFlag)
16358  {
16359  // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
16361  {
16362  ScreenLeftFlag = false; // 60 - 30
16363  }
16365  {
16366  ScreenRightFlag = false; // 60 - (60 - 30)
16367  }
16369  {
16370  ScreenUpFlag = false; // 36 - 18
16371  }
16373  {
16374  ScreenDownFlag = false; // 36 - (36 - 18)
16375  }
16376  }
16377  else
16378  {
16379  // prevent if less than a quarter of a screen visible (width = 240, height = 144)
16381  {
16382  ScreenLeftFlag = false; // 240 - 60
16383  }
16385  {
16386  ScreenRightFlag = false; // 240 - (240 - 60)
16387  }
16389  {
16390  ScreenUpFlag = false; // 144 - 36
16391  }
16393  {
16394  ScreenDownFlag = false; // 144 - (144 - 36)
16395  }
16396  }
16398  {
16399  ZoomFlag = false;
16400  HomeFlag = false;
16401  NewHomeFlag = false;
16402  ScreenLeftFlag = false;
16403  ScreenRightFlag = false;
16404  ScreenUpFlag = false;
16405  ScreenDownFlag = false;
16406  }
16407  if(Display->ZoomOutFlag)
16408  {
16409 // NewHomeFlag = false;
16410  TrackBuildPanelEnabledFlag = false;
16411  TrackBuildPanelLabelCaptionStr = "Disabled";
16412  PrefDirPanelEnabledFlag = false;
16413  PrefDirPanelLabelCaptionStr = "Disabled";
16414  OperatingPanelEnabledFlag = false;
16415  OperatingPanelLabelCaptionStr = "Disabled";
16416  TimetablePanelEnabledFlag = false;
16417  TimetablePanelLabelCaptionStr = "Disabled";
16418  }
16419  if(Level1Mode == OperMode)
16420  {
16421  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true)
16422  // TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
16423  {
16424  MTBFEditBox->Enabled = false;
16425  OperatingPanelEnabledFlag = false;
16426  OperatingPanelLabelCaptionStr = "Disabled";
16427  ZoomFlag = false;
16428  HomeFlag = false;
16429  NewHomeFlag = false;
16430  ScreenLeftFlag = false;
16431  ScreenRightFlag = false;
16432  ScreenUpFlag = false;
16433  ScreenDownFlag = false;
16434  SaveOperatingImageMenuItem->Enabled = false;
16435  }
16436  else
16437  {
16438  MTBFEditBox->Enabled = true;
16439  SaveOperatingImageMenuItem->Enabled = true;
16440  }
16441  }
16442  if(LocationNameTextBox->Visible)
16443  {
16444  ZoomFlag = false;
16445  HomeFlag = false;
16446  NewHomeFlag = false;
16447  ScreenLeftFlag = false;
16448  ScreenRightFlag = false;
16449  ScreenUpFlag = false;
16450  ScreenDownFlag = false;
16451  }
16452  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
16453  {
16454  ZoomFlag = false;
16455  HomeFlag = false;
16456  NewHomeFlag = false;
16457  ScreenLeftFlag = false;
16458  ScreenRightFlag = false;
16459  ScreenUpFlag = false;
16460  ScreenDownFlag = false;
16461  }
16462  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
16463  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
16464  {
16465  ZoomFlag = false;
16466  HomeFlag = false;
16467  NewHomeFlag = false;
16468  ScreenLeftFlag = false;
16469  ScreenRightFlag = false;
16470  ScreenUpFlag = false;
16471  ScreenDownFlag = false;
16472  }
16475  {
16476  ZoomFlag = false;
16477  }
16478  if(ZoomFlag)
16479  {
16480  ZoomButton->Enabled = true;
16481  }
16482  else
16483  {
16484  ZoomButton->Enabled = false;
16485  }
16486  if(HomeFlag)
16487  {
16488  HomeButton->Enabled = true;
16489  }
16490  else
16491  {
16492  HomeButton->Enabled = false;
16493  }
16494  if(NewHomeFlag)
16495  {
16496  NewHomeButton->Enabled = true;
16497  }
16498  else
16499  {
16500  NewHomeButton->Enabled = false;
16501  }
16502  if(ScreenLeftFlag)
16503  {
16504  ScreenLeftButton->Enabled = true;
16505  }
16506  else
16507  {
16508  ScreenLeftButton->Enabled = false;
16509  }
16510  if(ScreenRightFlag)
16511  {
16512  ScreenRightButton->Enabled = true;
16513  }
16514  else
16515  {
16516  ScreenRightButton->Enabled = false;
16517  }
16518  if(ScreenUpFlag)
16519  {
16520  ScreenUpButton->Enabled = true;
16521  }
16522  else
16523  {
16524  ScreenUpButton->Enabled = false;
16525  }
16526  if(ScreenDownFlag)
16527  {
16528  ScreenDownButton->Enabled = true;
16529  }
16530  else
16531  {
16532  ScreenDownButton->Enabled = false;
16533  }
16534  if(OperatingPanelEnabledFlag)
16535  {
16536  OperatingPanel->Enabled = true;
16537  }
16538  else
16539  {
16540  OperatingPanel->Enabled = false;
16541  }
16542  if(TrackBuildPanelEnabledFlag)
16543  {
16544  TrackBuildPanel->Enabled = true;
16545  }
16546  else
16547  {
16548  TrackBuildPanel->Enabled = false;
16549  }
16550  if(PrefDirPanelEnabledFlag)
16551  {
16552  PrefDirPanel->Enabled = true;
16553  }
16554  else
16555  {
16556  PrefDirPanel->Enabled = false;
16557  }
16558  if(TimetablePanelEnabledFlag)
16559  {
16560  TimetablePanel->Enabled = true;
16561  }
16562  else
16563  {
16564  TimetablePanel->Enabled = false;
16565  }
16566  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
16567  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
16568  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
16569  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
16570 
16571 // check if any CallingOnFlags set & set button accordingly
16572  if(Display->ZoomOutFlag)
16573  {
16574  CallingOnButton->Enabled = false;
16575  CallingOnButton->Down = false;
16576  }
16577  else
16578  {
16579  if(Level2OperMode == Operating)
16580  {
16581  bool CallOnValid = false;
16582  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
16583  {
16585  {
16586  CallingOnButton->Enabled = true;
16587  CallOnValid = true;
16588  }
16589  }
16590  if(!CallOnValid)
16591  {
16592  CallingOnButton->Enabled = false;
16593  CallingOnButton->Down = false;
16594  }
16595  }
16596  else
16597  {
16598  CallingOnButton->Enabled = false;
16599  CallingOnButton->Down = false;
16600  }
16601  }
16602  Utilities->CallLogPop(970);
16603 }
16604 
16605 // ---------------------------------------------------------------------------
16606 
16607 void TInterface::ErrorLog(int Caller, AnsiString Message)
16608 {
16609 // create an error file for diagnostic purposes called on detection of a runtime error
16610 
16611 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
16612 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
16613 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
16614 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
16615 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
16616 // depending on the time taken to press Exit.
16617 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
16618 
16619  if(ErrorLogCalledFlag)
16620  {
16621  return;
16622  }
16623  ErrorLogCalledFlag = true;
16624  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
16625  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
16626  SaveErrorFile();
16627  if((TempTTFileName != "") && FileExists(TempTTFileName))
16628  {
16629  DeleteFile(TempTTFileName);
16630  }
16631  Display->GetImage()->Visible = false;
16632  PerformancePanel->Visible = false;
16633  OperatorActionPanel->Visible = false; // new v2.2.0
16634  TrackBuildPanel->Visible = false;
16635  TrackElementPanel->Visible = false;
16636  LocationNameTextBox->Visible = false;
16637  TextBox->Visible = false;
16638  TrackLengthPanel->Visible = false;
16639  InfoPanel->Visible = false;
16640  PrefDirPanel->Visible = false;
16641  TimetablePanel->Visible = false;
16642  TimetableEditPanel->Visible = false;
16643  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
16644  OperatingPanel->Visible = false;
16645  FloatingPanel->Visible = false;
16646  ModeMenu->Enabled = false;
16647  SigImagePanel->Visible = false; // new at v2.3.0
16648  FileMenu->Enabled = false;
16649  EditMenu->Enabled = false;
16650  FloatingInfoMenu->Enabled = false;
16651  HelpMenu->Enabled = false;
16652 // SaveHeaderMenu1->Enabled = false;
16653  ScreenLeftButton->Visible = false;
16654  ScreenRightButton->Visible = false;
16655  ScreenUpButton->Visible = false;
16656  ScreenDownButton->Visible = false;
16657  HomeButton->Visible = false;
16658  NewHomeButton->Visible = false;
16659  ZoomButton->Visible = false;
16660  PrefDirKey->Visible = false;
16661  DistanceKey->Visible = false;
16662  RecoverClipboardMessageSent = true; // to stop paste message being given if recover clipboard error
16663  OutputLog1->Caption = "";
16664  OutputLog2->Caption = "";
16665  OutputLog3->Caption = "";
16666  OutputLog4->Caption = "";
16667  OutputLog5->Caption = "";
16668  OutputLog6->Caption = "";
16669  OutputLog7->Caption = "";
16670  OutputLog8->Caption = "";
16671  OutputLog9->Caption = "";
16672  OutputLog10->Caption = "";
16673  if(Caller == 113)
16674  {
16675  ErrorMessageStoreImage->Visible = true;
16676  }
16677  else
16678  {
16679  ErrorMessage->Visible = true;
16680  }
16681  ErrorButton->Visible = true;
16682  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
16683 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
16684 // is to close the program when the exit button is pressed
16685 }
16686 
16687 // ---------------------------------------------------------------------------
16688 
16690 // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
16691 {
16692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
16693  if(FloatingPanel->Visible == false)
16694  {
16695  Utilities->CallLogPop(1205);
16696  return(false);
16697  }
16698 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
16699  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
16700  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
16701  {
16702  Utilities->CallLogPop(1206);
16703  return(false);
16704  }
16705  else
16706  {
16707  Utilities->CallLogPop(1207);
16708  return(true);
16709  }
16710 }
16711 // ---------------------------------------------------------------------------
16712 
16713 void TInterface::SetCaption(int Caller)
16714 {
16715 /*
16716  NamedRailway; RlyFile; NamedTimetable
16717  n x x "New railway under development";
16718  y n x RailwayTitle + ": under development";
16719  y y n RailwayTitle + ": no timetable loaded";
16720  y y y RailwayTitle + ", " + TimetableTitle;
16721 */
16722 
16723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
16724  if(RailwayTitle == "")
16725  {
16726  Caption = "Railway: New railway under development";
16727  }
16728  else if(!RlyFile)
16729  {
16730  Caption = "Railway: " + RailwayTitle + " under development";
16731  }
16732 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
16733  else if(TimetableTitle == "")
16734  {
16735  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
16736  }
16737  else
16738  {
16739  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
16740  }
16741  Utilities->CallLogPop(1208);
16742 }
16743 
16744 // ---------------------------------------------------------------------------
16745 
16746 void TInterface::ResetAll(int Caller)
16747 {
16748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
16749  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
16751  Track->GapFlashRedPosition = -1;
16752  Track->GapFlashFlag = false;
16753  Track->RouteFlashFlag = false;
16754  Track->PointFlashFlag = false;
16756  AutoSigsFlag = false;
16757  PreventGapOffsetResetting = false;
16758 
16759  Utilities->Clock2Stopped = false;
16760  TTClockSpeed = 1;
16761  TTClockSpeedLabel->Caption = "x1";
16762  Track->SetTrackFinished(false);
16764  CurrentSpeedButton = 0; // not assigned yet
16766  StartX = 0;
16767  StartY = 0;
16768  mbLeftDown = false;
16770  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
16772  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
16774  WarningFlashCount = 0;
16775 
16776  Level1Mode = BaseMode;
16777  SetLevel1Mode(26);
16778  RouteMode = None;
16779  PreferredRoute = true; // default starting conditions
16780  ConsecSignalsRoute = true; // default starting conditions
16781  DevelopmentPanel->Visible = false;
16782 
16783  MainScreen->Canvas->CopyMode = cmSrcCopy;
16784  FloatingPanel->Visible = false;
16785  OverallDistance = 0;
16786  OverallSpeedLimit = -1;
16787  AllRoutes->RouteTruncateFlag = false;
16788  CallingOnButton->Down = false;
16789  Display->ZoomOutFlag = false;
16790  ScreenGridFlag = false;
16791  InfoCaptionStore = "";
16792  ErrorLogCalledFlag = false;
16793  ErrorMessage->Visible = false;
16794  ErrorMessageStoreImage->Visible = false;
16795  TempCursorSet = false;
16796  TempCursor = TCursor(-2); // Arrow
16797  WholeRailwayMoving = false; // new at v2.1.0
16798 
16799  TrainController->TTClockTime = TDateTime(0); // default setting
16800  TTClockAdjPanel->Visible = false;
16802  ConflictPanel->Visible = false;
16803  SelectedTrainID = -1;
16804  SetTrackBuildImages(11);
16805 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
16806 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
16807 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
16808  Track->CalcHLocMinEtc(8);
16809  FileChangedFlag = false;
16810  RlyFile = false;
16811  SaveSessionFlag = false;
16812  LoadSessionFlag = false;
16813  SelectionValid = false;
16814  TimetableChangedFlag = false;
16815  SavedFileName = "";
16816  RailwayTitle = "";
16817  TimetableTitle = "";
16818  SetCaption(1);
16819  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
16820  // added for Beta v0.2b
16821  CreateEditTTTitle = ""; // as above
16822  AllRoutes->NextRouteID = 0;
16823  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
16824  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
16825 
16826  TempFont->Style.Clear();
16827  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
16828  TempFont->Size = 10;
16829  TempFont->Color = clB0G0R0;
16830  TempFont->Charset = (TFontCharset)(0);
16831  MainScreen->Canvas->Font->Assign(TempFont);
16832  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
16833  PerformancePanel->Left = MainScreen->Left;
16834  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
16835  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
16836  ; // new v2.2.0
16837  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
16838  // ScreenLeftButton->Left = ScreenRightButton->Left;
16839  // ScreenUpButton->Left = ScreenRightButton->Left;
16840  // ScreenDownButton->Left = ScreenRightButton->Left;
16841  // HomeButton->Left = ScreenRightButton->Left;
16842  // NewHomeButton->Left = ScreenRightButton->Left;
16843  // ZoomButton->Left = ScreenRightButton->Left;
16844  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
16845  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width;
16846  ; // new v2.2.0
16847 
16848  delete TempFont;
16849  CtrlKey = false;
16850  ShiftKey = false;
16851  ClipboardChecked = false;
16852  Utilities->CallLogPop(1209);
16853 }
16854 
16855 // ---------------------------------------------------------------------------
16856 
16858 {
16859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
16860  if((Level1Mode == OperMode) || RlyFile)
16861  {
16862  TrackLinkedImage->Visible = false;
16863  TrackNotLinkedImage->Visible = false;
16864  GapsSetImage->Visible = false;
16865  GapsNotSetImage->Visible = false;
16866  LocationNamesSetImage->Visible = false;
16867  LocationNamesNotSetImage->Visible = false;
16868  Utilities->CallLogPop(1114);
16869  return;
16870  }
16871  else
16872  {
16873  if(!Track->NoActiveTrack(9))
16874  {
16875  if(Track->IsTrackFinished())
16876  {
16877  TrackLinkedImage->Visible = true;
16878  TrackNotLinkedImage->Visible = false;
16879  }
16880  else
16881  {
16882  TrackNotLinkedImage->Visible = true;
16883  TrackLinkedImage->Visible = false;
16884  }
16885  }
16886  else
16887  {
16888  TrackLinkedImage->Visible = false;
16889  TrackNotLinkedImage->Visible = false;
16890  }
16891  if(!Track->NoGaps(1))
16892  {
16893  if(Track->GapsUnset(6))
16894  {
16895  GapsNotSetImage->Visible = true;
16896  GapsSetImage->Visible = false;
16897  }
16898  else
16899  {
16900  GapsNotSetImage->Visible = false;
16901  GapsSetImage->Visible = true;
16902  }
16903  }
16904  else
16905  {
16906  GapsNotSetImage->Visible = false;
16907  GapsSetImage->Visible = false;
16908  }
16910  {
16911  if(Track->LocationsNotNamed(0))
16912  {
16913  LocationNamesSetImage->Visible = false;
16914  LocationNamesNotSetImage->Visible = true;
16915  }
16916  else
16917  {
16918  LocationNamesSetImage->Visible = true;
16919  LocationNamesNotSetImage->Visible = false;
16920  }
16921  }
16922  else
16923  {
16924  LocationNamesSetImage->Visible = false;
16925  LocationNamesNotSetImage->Visible = false;
16926  }
16927  }
16928  Utilities->CallLogPop(1113);
16929 }
16930 
16931 // ---------------------------------------------------------------------------
16932 
16933 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
16934 {
16935  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
16936  FileChangedFlag = true;
16937  if(NonPrefDirChangesMade)
16938  {
16939  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
16940  {
16941  RailwayTitle = "";
16942  TimetableTitle = "";
16943  SavedFileName = "";
16944  RlyFile = false;
16945  }
16946  TimetableTitle = ""; // should have been reset already during user mode change but include here also
16947  SetTrackBuildImages(15);
16948  }
16949  SetCaption(2);
16950  Utilities->CallLogPop(1210);
16951 }
16952 
16953 // ---------------------------------------------------------------------------
16954 
16955 void TInterface::SaveSession(int Caller)
16956 {
16957  // ExcessLCDownMins saved as string after ***Interface*** see below
16958  try
16959  {
16960  TrainController->LogEvent("SaveSession");
16961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
16962  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
16963  Screen->Cursor = TCursor(-11); // Hourglass;
16964  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
16965  // avoid characters in filename:= / \ : * ? " < > |
16966  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
16967  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
16968 // SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
16969 // "; " + TimetableTitle + ".ssn";
16970  SessionFileStr = LoadSessionDialog->InitialDir + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
16971  "; " + TimetableTitle + ".ssn";
16972  std::ofstream SessionFile(SessionFileStr.c_str());
16973  if(!(SessionFile.fail()))
16974  {
16975  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
16976 // added ExcessLC... at v2.2.0 as omitted earlier
16977  SaveInterface(0, SessionFile);
16978  // save track elements
16979  Utilities->SaveFileString(SessionFile, "***Track***");
16980  if(Track->UserGraphicVector.empty())
16981  {
16982  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
16983  }
16984  else
16985  {
16986  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
16987  }
16988  // save text elements
16989  Utilities->SaveFileString(SessionFile, "***Text***");
16990  TextHandler->SaveText(2, SessionFile);
16991  // save PrefDir elements
16992  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
16993  EveryPrefDir->SavePrefDirVector(2, SessionFile);
16994  if(!Track->UserGraphicVector.empty())
16995  {
16996  // save user graphics
16997  Track->SaveUserGraphics(2, SessionFile);
16998  }
16999  // save routes
17000  Utilities->SaveFileString(SessionFile, "***Routes***");
17001  AllRoutes->SaveRoutes(0, SessionFile);
17002  // save LockedRoutes
17003  Utilities->SaveFileString(SessionFile, "***Locked routes***");
17004  TrainController->SaveSessionLockedRoutes(0, SessionFile);
17005  // save ContinuationAutoSigEntries
17006  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
17008  // save BarriersDownVector
17009  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
17010  Track->SaveSessionBarriersDownVector(0, SessionFile);
17011  // save timetable
17012  Utilities->SaveFileString(SessionFile, "***Timetable***");
17013  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
17014  {
17015  SessionFile.close();
17016  DeleteFile(SessionFileStr);
17017  Screen->Cursor = TCursor(-2); // Arrow;
17018  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
17019  Utilities->CallLogPop(1150);
17020  return;
17021  }
17022  // save TimetableClock
17023  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
17024  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
17025 
17026  // save trains
17027  Utilities->SaveFileString(SessionFile, "***Trains***");
17028  TrainController->SaveSessionTrains(0, SessionFile);
17029  // save performance file
17030  Utilities->SaveFileString(SessionFile, "***Performance file***");
17031  SavePerformanceFile(0, SessionFile);
17032  Utilities->SaveFileString(SessionFile, "***End of performance file***");
17033 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
17034  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
17037  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
17038  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17039  {
17041  {
17044  }
17045  }
17046  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
17047  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
17048 // end of v2.4.0 addition
17049 
17050 // added at v2.7.0
17051  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
17052  Utilities->SaveFileString(SessionFile, "End of file at v2.7.0");
17053 // end of v2.7.0 addition
17054  SessionFile.close();
17055  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
17056  RailwayTitle + "; " + TimetableTitle + ".ssn");
17058 // to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
17059  }
17060  else
17061  {
17062  TrainController->StopTTClockMessage(5, "Session file failed to open - reason not known, session unable to be saved.");
17063  }
17065  Screen->Cursor = TCursor(-2); // Arrow
17066  Utilities->CallLogPop(1141);
17067  }
17068  catch(const Exception &e)
17069  {
17070  ErrorLog(40, e.Message);
17071  }
17072 }
17073 
17074 // ---------------------------------------------------------------------------
17075 
17076 void TInterface::LoadSession(int Caller)
17077 // always loads in 'Paused' or 'PreStart' mode
17078 {
17079 // remember to load the timetable clock
17080 // no routes in build
17081 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
17082 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
17083 // set RlyFile true
17084  try
17085  {
17086  TrainController->LogEvent("LoadSession");
17087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
17088  if(!ClearEverything(4))
17089  {
17090  Utilities->CallLogPop(1145);
17091  return;
17092  }
17093  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
17094  if(LoadSessionDialog->Execute())
17095  {
17096  if(LoadSessionDialog->InitialDir != TPath::GetDirectoryName(LoadSessionDialog->FileName)) // new at v2.6.0 to retain a new directory
17097  {
17098  LoadSessionDialog->InitialDir = TPath::GetDirectoryName(LoadSessionDialog->FileName);
17099  }
17100  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
17101  Screen->Cursor = TCursor(-11); // Hourglass;
17102  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
17103  // if(true)
17104  {
17105  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
17106  if(!(SessionFile.fail()))
17107  {
17108  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
17109  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
17110  AnsiString TempString = Utilities->LoadFileString(SessionFile);
17111 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
17112 
17113  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
17114  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
17115  // can't find it or no value for Excess LCDownMins, either way count as zero
17116  {
17118  }
17119  else
17120  {
17121  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
17122  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
17123  {
17125  }
17126  else
17127  {
17128  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
17129  }
17130  } // end of v2.2.0 * v2.4.0 additions
17131 
17132  LoadInterface(0, SessionFile);
17133  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
17134  int TempDisplayOffsetV = Display->DisplayOffsetV;
17135  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
17136  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
17137  bool GraphicsFollow = false;
17138  // load track elements
17139  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
17140  Track->LoadTrack(4, SessionFile, GraphicsFollow);
17141  // load text elements
17142  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
17143  TextHandler->LoadText(1, SessionFile);
17144  // load PrefDir elements
17145  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
17146  EveryPrefDir->LoadPrefDir(1, SessionFile);
17147  if(GraphicsFollow)
17148  {
17149  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
17150  }
17152  {
17153  SessionFile.close();
17154  Screen->Cursor = TCursor(-2); // Arrow;
17155  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
17156  Utilities->CallLogPop(1438);
17157  return;
17158  }
17159  // load routes
17160  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
17161  if(!AllRoutes->LoadRoutes(0, SessionFile))
17162  {
17163  SessionFile.close();
17164  Screen->Cursor = TCursor(-2); // Arrow;
17165  ShowMessage("Corruption in route section of the session file, session can't be loaded");
17166  Utilities->CallLogPop(1439);
17167  return;
17168  }
17169  // load LockedRoutes
17170  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
17171  TrainController->LoadSessionLockedRoutes(0, SessionFile);
17172  // load ContinuationAutoSigEntries
17173  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
17175  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
17176  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
17177  if(TempString == "***BarriersDownVector***")
17178  {
17179  Track->LoadBarriersDownVector(0, SessionFile);
17180  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
17181  }
17182  // load timetable (marker "***Timetable***" already loaded)
17183  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
17184  {
17185  SessionFile.close();
17186  Screen->Cursor = TCursor(-2); // Arrow;
17187  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
17188  Utilities->CallLogPop(1151);
17189  return;
17190  }
17191  // TimetableTitle should be loaded at this stage - check
17192  if(TimetableTitle == "")
17193  {
17194  SessionFile.close();
17195  Screen->Cursor = TCursor(-2); // Arrow;
17196  throw Exception("TimetableTitle null in LoadSession");
17197  }
17198  // load timetable clock
17199  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
17200  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
17201  // load trains
17202  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
17203  TrainController->LoadSessionTrains(0, SessionFile);
17204  // load performance file + populate the performance log
17205  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
17206  // first reset the performance file name and open it before reloading it
17207  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
17208  // avoid characters in filename:= / \ : * ? " < > |
17209  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
17210  TimetableTitle + ".txt";
17211  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
17212  if(Utilities->PerformanceFile.fail())
17213  {
17214  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
17215  " in the folder where the 'Railway.exe' program file resides");
17216  }
17217  // now reload the performance file
17218  LoadPerformanceFile(0, SessionFile);
17219  // addition at v2.4.0
17220  char TempChar;
17221  SessionFile.get(TempChar);
17222  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
17223  {
17224  SessionFile.get(TempChar);
17225  }
17226  if(SessionFile.eof()) // end of file
17227  {
17230  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
17231  // at v2.7.0 if find eof then don't need a value for ConsecSignalsRoute as that loaded same as PreferredRoute in interface
17232  }
17233  else
17234  {
17235  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
17236  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
17237  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
17238  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
17239  // now load any failed trains along with their OriginalPowerAtRail values
17240  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
17241  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
17242  double PowerDouble;
17243  while(ID != -1)
17244  {
17245  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
17248  ID = Utilities->LoadFileInt(SessionFile);
17249  }
17250  // added at v2.7.0 - need value for ConsecSignalsRoute but might have eof here with older sessions so first test for that
17251  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.4.0" discarded
17252  SessionFile.get(TempChar);
17253  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
17254  {
17255  SessionFile.get(TempChar);
17256  }
17257  if(!SessionFile.eof()) // not end of file
17258  {
17259  if((TempChar != '0') && (TempChar != '1'))
17260  {
17261  throw Exception("TempChar value = " + AnsiString(TempChar) + ", should be 0 or 1");
17262  }
17263  ConsecSignalsRoute = true;
17264  if(TempChar == '0')
17265  {
17266  ConsecSignalsRoute = false;
17267  }
17268  }
17269  SessionFile.close(); //
17270  }
17271  // deal with other settings
17272  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
17273  Display->DisplayOffsetV = TempDisplayOffsetV;
17274  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
17275  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
17276  // now set attributes to 1 for all LCs with barriers down
17277  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
17278  {
17280  }
17281  Track->ChangingLCVector.clear();
17282  Track->CalcHLocMinEtc(10);
17284  SetLevel1Mode(27);
17285  if(Level2OperMode == PreStart)
17286  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
17287  {
17288  // then delay unspecified though seems to be 0
17289  PointsFlashDuration = 0.0;
17292  }
17293  else
17294  {
17298  }
17299  RlyFile = true;
17300  SetCaption(3);
17302  }
17303  }
17304  else
17305  {
17306  ShowMessage("Session file integrity check failed, unable to load session.");
17307  }
17308  Screen->Cursor = TCursor(-2); // Arrow;
17309  }
17310  Utilities->CallLogPop(1146);
17311  }
17312  catch(const Exception &e)
17313  {
17314  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
17315  {
17316  Screen->Cursor = TCursor(-2); // Arrow;
17317  OutputLog1->Caption = "";
17318  OutputLog2->Caption = "";
17319  OutputLog3->Caption = "";
17320  OutputLog4->Caption = "";
17321  OutputLog5->Caption = "";
17322  OutputLog6->Caption = "";
17323  OutputLog7->Caption = "";
17324  OutputLog8->Caption = "";
17325  OutputLog9->Caption = "";
17326  OutputLog10->Caption = "";
17327  UnicodeString MessageStr =
17328  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
17329 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
17330  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
17331  Application->Terminate();
17332  }
17333  else
17334  {
17335  ErrorLog(41, e.Message);
17336  }
17337  }
17338 }
17339 
17340 // ---------------------------------------------------------------------------
17341 
17342 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
17343 {
17344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
17345  if(Level2OperMode == PreStart)
17346  {
17347  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
17348  }
17349  else
17350  {
17351  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
17352  }
17353  Utilities->SaveFileString(SessionFile, RailwayTitle);
17354  Utilities->SaveFileString(SessionFile, TimetableTitle);
17355  Utilities->SaveFileBool(SessionFile, PreferredRoute);
17356  Utilities->SaveFileBool(SessionFile, PreferredRoute);
17357 // changed at v2.7.0, was ConsecSignalsRoute here but if different to PreferredRoute (as can be from v2.7.0) then have
17358  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
17359 // error if try to load with an earlier prog version. ConsecSignalsRoute now moved to end of session file
17360  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
17361  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
17366  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
17367  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
17368  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
17369  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
17370  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
17371  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
17372  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
17373  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
17374  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
17375  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
17376 
17398  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
17399  Utilities->CallLogPop(1211);
17400 }
17401 
17402 // ---------------------------------------------------------------------------
17403 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
17404 {
17405  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
17406  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
17407 
17408  if(OpMode == "PreStart")
17409  {
17411  }
17412  else
17413  {
17415  }
17416  RailwayTitle = Utilities->LoadFileString(SessionFile);
17417  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
17418 
17419  TimetableTitle = Utilities->LoadFileString(SessionFile);
17420  PreferredRoute = Utilities->LoadFileBool(SessionFile);
17421  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
17422  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
17423  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
17424  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
17429  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
17430  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
17431  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
17432  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
17433  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
17434  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
17435  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
17436  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
17437  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
17438  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
17439 
17447  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
17461  Utilities->CallLogPop(1212);
17462 }
17463 
17464 // ---------------------------------------------------------------------------
17465 
17466 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
17467 {
17468  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
17469 
17470  AnsiString OpMode = "";
17471 
17472  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
17473  {
17474  Utilities->CallLogPop(1767);
17475  return(false);
17476  }
17477  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
17478  {
17479  Utilities->CallLogPop(1768);
17480  return(false);
17481  }
17482  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
17483  {
17484  Utilities->CallLogPop(1213);
17485  return(false);
17486  }
17487  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
17488  {
17489  Utilities->CallLogPop(1214);
17490  return(false);
17491  }
17492  if(!Utilities->CheckFileBool(SessionFile))
17493  {
17494  Utilities->CallLogPop(1216);
17495  return(false);
17496  }
17497  if(!Utilities->CheckFileBool(SessionFile))
17498  {
17499  Utilities->CallLogPop(1217);
17500  return(false);
17501  }
17502  if(!Utilities->CheckFileBool(SessionFile))
17503  {
17504  Utilities->CallLogPop(1218);
17505  return(false);
17506  }
17507  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17508  {
17509  Utilities->CallLogPop(1409);
17510  return(false);
17511  }
17512  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17513  {
17514  Utilities->CallLogPop(1486);
17515  return(false);
17516  }
17517  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17518  {
17519  Utilities->CallLogPop(1487);
17520  return(false);
17521  }
17522  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17523  {
17524  Utilities->CallLogPop(1488);
17525  return(false);
17526  }
17527  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17528  {
17529  Utilities->CallLogPop(1489);
17530  return(false);
17531  }
17532  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
17533  {
17534  Utilities->CallLogPop(1528);
17535  return(false);
17536  }
17537  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17538  {
17539  Utilities->CallLogPop(1725);
17540  return(false);
17541  }
17542  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17543  {
17544  Utilities->CallLogPop(1726);
17545  return(false);
17546  }
17547  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17548  {
17549  Utilities->CallLogPop(1727);
17550  return(false);
17551  }
17552  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17553  {
17554  Utilities->CallLogPop(1728);
17555  return(false);
17556  }
17557  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17558  {
17559  Utilities->CallLogPop(1730);
17560  return(false);
17561  }
17562  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17563  {
17564  Utilities->CallLogPop(1731);
17565  return(false);
17566  }
17567  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17568  {
17569  Utilities->CallLogPop(1732);
17570  return(false);
17571  }
17572  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17573  {
17574  Utilities->CallLogPop(1733);
17575  return(false);
17576  }
17577  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17578  {
17579  Utilities->CallLogPop(1734);
17580  return(false);
17581  }
17582  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
17583  {
17584  Utilities->CallLogPop(1789);
17585  return(false);
17586  }
17587  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17588  {
17589  Utilities->CallLogPop(1737);
17590  return(false);
17591  }
17592  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17593  {
17594  Utilities->CallLogPop(1738);
17595  return(false);
17596  }
17597  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17598  {
17599  Utilities->CallLogPop(1739);
17600  return(false);
17601  }
17602  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17603  {
17604  Utilities->CallLogPop(1740);
17605  return(false);
17606  }
17607  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17608  {
17609  Utilities->CallLogPop(1741);
17610  return(false);
17611  }
17612  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17613  {
17614  Utilities->CallLogPop(1742);
17615  return(false);
17616  }
17617  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17618  {
17619  Utilities->CallLogPop(1743);
17620  return(false);
17621  }
17622  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17623  {
17624  Utilities->CallLogPop(1744);
17625  return(false);
17626  }
17627  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17628  {
17629  Utilities->CallLogPop(1745);
17630  return(false);
17631  }
17632  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17633  {
17634  Utilities->CallLogPop(1746);
17635  return(false);
17636  }
17637  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17638  {
17639  Utilities->CallLogPop(1747);
17640  return(false);
17641  }
17642  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17643  {
17644  Utilities->CallLogPop(1748);
17645  return(false);
17646  }
17647  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17648  {
17649  Utilities->CallLogPop(1749);
17650  return(false);
17651  }
17652  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17653  {
17654  Utilities->CallLogPop(1750);
17655  return(false);
17656  }
17657  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17658  {
17659  Utilities->CallLogPop(1751);
17660  return(false);
17661  }
17662  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
17663  {
17664  Utilities->CallLogPop(1752);
17665  return(false);
17666  }
17667  if(!Utilities->CheckFileDouble(SessionFile))
17668  {
17669  Utilities->CallLogPop(1753);
17670  return(false);
17671  }
17672  if(!Utilities->CheckFileDouble(SessionFile))
17673  {
17674  Utilities->CallLogPop(1754);
17675  return(false);
17676  }
17677  if(!Utilities->CheckFileDouble(SessionFile))
17678  {
17679  Utilities->CallLogPop(1755);
17680  return(false);
17681  }
17682  if(!Utilities->CheckFileDouble(SessionFile))
17683  {
17684  Utilities->CallLogPop(1756);
17685  return(false);
17686  }
17687  if(!Utilities->CheckFileDouble(SessionFile))
17688  {
17689  Utilities->CallLogPop(1757);
17690  return(false);
17691  }
17692  Utilities->CallLogPop(1219);
17693  return(true);
17694 }
17695 
17696 // ---------------------------------------------------------------------------
17697 
17698 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
17699 {
17700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
17701  if(!FileExists(TempTTFileName))
17702  {
17703  Utilities->CallLogPop(1862);
17704  return(false);
17705  }
17706  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
17707  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
17708 
17709  int Handle = FileOpen(TempTTFileName, fmOpenRead);
17710  int Count = 0;
17711 
17712  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
17713  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
17714  // then, but nevertheless have 10 retries before giving message to be on safe side
17715  {
17716  Handle = FileOpen(TempTTFileName, fmOpenRead);
17717  Count++;
17718  Delay(1, 50); // 50mSec delay between tries
17719  if(Count > 10)
17720  {
17721  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
17722  Utilities->CallLogPop(1221);
17723  return(false);
17724  }
17725  }
17726 
17727  char *Buffer = new char[10000];
17728  int BytesRead;
17729 
17730  while(true)
17731  {
17732  BytesRead = FileRead(Handle, Buffer, 10000);
17733  SessionFile.write(Buffer, BytesRead);
17734  if(BytesRead < 10000)
17735  {
17736  break;
17737  }
17738  }
17739  delete[]Buffer;
17740  FileClose(Handle);
17741 
17742  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
17743  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
17744 
17745  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
17746 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
17747  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
17748  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
17749  {
17750  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
17751  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
17752  {
17753  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
17754  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
17755  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
17756  }
17757  }
17758  Utilities->CallLogPop(1220);
17759  return(true);
17760 }
17761 
17762 // ---------------------------------------------------------------------------
17763 
17764 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
17765 {
17766  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
17767  if(!FileExists(TimetableFileName))
17768  {
17769  Utilities->CallLogPop(1863);
17770  return(false);
17771  }
17772  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
17773  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
17774 
17775  int Handle = FileOpen(TimetableFileName, fmOpenRead);
17776  int Count = 0;
17777 
17778  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
17779  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
17780  // then, but nevertheless have 10 retries before giving message to be on safe side
17781  {
17782  Handle = FileOpen(TimetableFileName, fmOpenRead);
17783  Count++;
17784  Delay(5, 50); // 50mSec delay between tries
17785  if(Count > 10)
17786  {
17787  Utilities->CallLogPop(1835);
17788  return(false);
17789  }
17790  }
17791 
17792  char *Buffer = new char[10000];
17793  int BytesRead;
17794 
17795  while(true)
17796  {
17797  BytesRead = FileRead(Handle, Buffer, 10000);
17798  ErrorFile.write(Buffer, BytesRead);
17799  if(BytesRead < 10000)
17800  {
17801  break;
17802  }
17803  }
17804  delete[]Buffer;
17805  FileClose(Handle);
17806 
17807  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
17808  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
17809 
17810  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
17811  Utilities->CallLogPop(1836);
17812  return(true);
17813 }
17814 
17815 // ---------------------------------------------------------------------------
17816 
17817 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
17818 // the .ttb section is delimited by "***End***"
17819 // create the temporary timetable file in the working folder exactly like the original
17820 {
17821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
17822  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
17823  TrainController->SSHigh = false;
17824  TrainController->MRSHigh = false;
17825  TrainController->MRSLow = false;
17826  TrainController->MassHigh = false;
17827  TrainController->BFHigh = false;
17828  TrainController->BFLow = false;
17829  TrainController->PwrHigh = false;
17830  TrainController->SigSHigh = false;
17831  TrainController->SigSLow = false;
17832  if((TempTTFileName != "") && FileExists(TempTTFileName))
17833  {
17834  DeleteFile(TempTTFileName);
17835  }
17836  int TempTTFileNumber = 0;
17837 
17838  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
17839  {
17840  TempTTFileNumber++;
17841  }
17842  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
17843 
17844  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
17845  int Count;
17846  char Zero = '\0';
17847 
17848  if(!TTBFile.fail())
17849  {
17850  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
17851  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
17852  if(TempChar == '\n')
17853  {
17854  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
17855  }
17856  if(!SessionFile.getline(Buffer, 10000, '\0'))
17857  {
17858  TTBFile.close();
17859  DeleteFile(TempTTFileName);
17860  delete[]Buffer;
17861  Utilities->CallLogPop(1222);
17862  return(false);
17863  }
17864  Count = 0;
17865  for(int x = 0; x < 10000; x++)
17866  {
17867  if(Buffer[x] != '\0')
17868  {
17869  Count++;
17870  }
17871  else
17872  {
17873  break;
17874  }
17875  }
17876  while(AnsiString(Buffer) != "***End***")
17877  {
17878  TTBFile.write(Buffer, Count);
17879  TTBFile.write(&Zero, 1);
17880 // TTBFile.write(&NewLine, 1);
17881  if(!SessionFile.getline(Buffer, 10000, '\0'))
17882  {
17883  TTBFile.close();
17884  DeleteFile(TempTTFileName);
17885  delete[]Buffer;
17886  Utilities->CallLogPop(1223);
17887  return(false);
17888  }
17889  Count = 0;
17890  for(int x = 0; x < 10000; x++)
17891  {
17892  if(Buffer[x] != '\0')
17893  {
17894  Count++;
17895  }
17896  else
17897  {
17898  break;
17899  }
17900  }
17901  }
17902  TTBFile.close();
17903  delete[]Buffer;
17904 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
17905 // now create the internal timetable from the .tmp file
17906  bool GiveMessagesFalse = false;
17907  bool CheckLocationsExistInRailwayTrue = true;
17908  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
17909  {
17910  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
17911  if(TTBLFile.is_open())
17912  {
17913  bool SessionFileTrue = true;
17914  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
17915  {
17916  TTBLFile.close();
17917  DeleteFile(TempTTFileName);
17918  Utilities->CallLogPop(1224);
17919  return(false);
17920  }
17921  }
17922  else
17923  {
17924  DeleteFile(TempTTFileName);
17925  Utilities->CallLogPop(1225);
17926  return(false);
17927  }
17928  } // if(FileIntegrityCheck(TTBFileName.c_str()))
17929  else
17930  {
17931  DeleteFile(TempTTFileName);
17932  Utilities->CallLogPop(1226);
17933  return(false);
17934  }
17935 // DeleteFile(TempTTFileName); no, need to save it for later session saves
17936 
17937  // now need to load the TrainOperatingData so can be loaded back into the timetable
17938  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
17939  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
17940  {
17941  Utilities->CallLogPop(1811);
17942  return(false);
17943  }
17944  for(int x = 0; x < NumberOfTrainEntries; x++)
17945  {
17946  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
17947  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
17948  {
17949  Utilities->CallLogPop(1812);
17950  return(false);
17951  }
17952  for(int y = 0; y < NumberOfTrains; y++)
17953  {
17954  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
17955  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
17956  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
17957  }
17958  }
17959  Utilities->CallLogPop(1227);
17960  return(true);
17961  }
17962  else
17963  {
17964  Utilities->CallLogPop(1228);
17965  return(false);
17966  }
17967 }
17968 
17969 // ---------------------------------------------------------------------------
17970 
17971 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
17972 // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
17973 // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
17974 // trying to build a timetable - that's done during load
17975 {
17976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
17977  AnsiString OutString;
17978 
17979  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
17980  {
17981  Utilities->CallLogPop(1229);
17982  return(false);
17983  }
17984  while(OutString != "***End***")
17985  {
17986  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
17987  {
17988  Utilities->CallLogPop(1230);
17989  return(false);
17990  }
17991  }
17992 // now need to check the TrainOperatingData, which was saved in text mode
17993  if(SessionFile.fail())
17994  {
17995  Utilities->CallLogPop(1231);
17996  return(false);
17997  }
17998  int NumberOfTrainEntries;
17999 
18000  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
18001  {
18002  Utilities->CallLogPop(1232);
18003  return(false);
18004  }
18005  for(int x = 0; x < NumberOfTrainEntries; x++)
18006  {
18007  int NumberOfTrains;
18008  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
18009  {
18010  Utilities->CallLogPop(1233);
18011  return(false);
18012  }
18013  for(int y = 0; y < NumberOfTrains; y++)
18014  {
18015  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
18016  {
18017  Utilities->CallLogPop(1234);
18018  return(false);
18019  }
18020  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
18021  {
18022  Utilities->CallLogPop(1235);
18023  return(false);
18024  }
18025  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
18026  {
18027  Utilities->CallLogPop(1236);
18028  return(false);
18029  }
18030  }
18031  }
18032  Utilities->CallLogPop(1237);
18033  return(true);
18034 }
18035 
18036 // ---------------------------------------------------------------------------
18037 
18038 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
18039 {
18040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
18041  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
18042  bool EndOfFile = false;
18043  int Count = 0;
18044  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
18045 
18046  while(!EndOfFile)
18047  {
18048  TTBLFile.getline(TrainTimetableString, 10000, '\0');
18049  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
18050  {
18051  // may still have eof even if read a line (no CRLF at end), and
18052  // if so need to process it
18053  EndOfFile = true;
18054  break;
18055  }
18056  AnsiString OneLine(TrainTimetableString);
18057  bool FinalCallTrue = true;
18058  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
18059  CheckLocationsExistInRailway)) // get rid of lines before the start time
18060  {
18061  TTBLFile.getline(TrainTimetableString, 10000, '\0');
18062  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
18063  {
18064  TTBLFile.close();
18065  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
18066  }
18067  OneLine = AnsiString(TrainTimetableString);
18068  }
18069  // here when have accepted the start time
18070  if(Count == 0)
18071  {
18072  Count++; // increment past the start time
18073  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
18074  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
18075  {
18076  EndOfFile = true;
18077  OneLine = "";
18078  }
18079  else
18080  {
18081  OneLine = AnsiString(TrainTimetableString);
18082  }
18083  }
18084  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
18085  {
18086  TTBLFile.close();
18087  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
18088  }
18089  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
18090  {
18091  TTBLFile.close();
18092  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
18093  }
18094  Count++;
18095  }
18096  TTBLFile.close();
18097  delete[]TrainTimetableString;
18098 // here when first pass actions completed successfully
18099  if(!TrainController->SecondPassActions(0, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
18100  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
18101  // messages given in function if errors & vector cleared
18102  {
18103  if(GiveMessages)
18104  {
18105  ShowMessage("Timetable secondary integrity check failed - unable to load");
18106  }
18107  Utilities->CallLogPop(1238);
18108  return(false);
18109  }
18110  else
18111  {
18112 // TimetableLoaded = true;
18113  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
18114  {
18115  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
18116  {
18117  if(TimetableDialog->FileName[x] == '\\')
18118  {
18119  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
18120  SetCaption(4);
18121  break;
18122  }
18123  }
18124  }
18125 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
18126  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
18127  {
18128  Level1Mode = BaseMode;
18129  SetLevel1Mode(28);
18130  }
18131  }
18132  Utilities->CallLogPop(1239);
18133  return(true);
18134 }
18135 
18136 // ---------------------------------------------------------------------------
18137 
18138 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
18139 {
18140  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
18141  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
18142  bool EndOfFile = false;
18143  int Count = 0;
18144  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
18145 
18146  while(!EndOfFile)
18147  {
18148  TTBLFile.getline(TrainTimetableString, 10000, '\0');
18149  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
18150  {
18151  // may still have eof even if read a line (no CRLF at end), and
18152  // if so need to process it
18153  EndOfFile = true;
18154  break;
18155  }
18156  AnsiString OneLine(TrainTimetableString);
18157  bool FinalCallTrue = true;
18158  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
18159  CheckLocationsExistInRailway)) // get rid of lines before the start time
18160  {
18161  TTBLFile.getline(TrainTimetableString, 10000, '\0');
18162  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
18163  {
18164  TTBLFile.close();
18165  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
18166  }
18167  OneLine = AnsiString(TrainTimetableString);
18168  }
18169  // here when have accepted the start time
18170  if(Count == 0)
18171  {
18172  Count++; // increment past the start time
18173  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
18174  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
18175  {
18176  EndOfFile = true;
18177  OneLine = "";
18178  }
18179  else
18180  {
18181  OneLine = AnsiString(TrainTimetableString);
18182  }
18183  }
18184  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
18185  {
18186  TTBLFile.close();
18187  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
18188  }
18189  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
18190  {
18191  TTBLFile.close();
18192  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
18193  }
18194  Count++;
18195  }
18196  TTBLFile.close();
18197  delete[]TrainTimetableString;
18198 // here when first pass actions completed successfully
18199  if(!TrainController->SecondPassActions(1, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
18200  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
18201  // messages given in function if errors & vector cleared
18202  {
18203 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
18204 // above dropped in v2.4.0 as all called functions give own messages
18205  Utilities->CallLogPop(1665);
18206  return(false);
18207  }
18208  Utilities->CallLogPop(1666);
18209  return(true);
18210 }
18211 
18212 // ---------------------------------------------------------------------------
18213 
18214 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
18215 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
18216 relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
18217 before loading.
18218 
18219 Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
18220 all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
18221 which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
18222 in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
18223 
18224 Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
18225 would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
18226 */
18227 {
18228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
18229  std::ifstream InFile(FileName.c_str());
18230 // first pass as far as timetable
18231  int NumberOfActiveElements;
18232  bool GraphicsFollow = false;
18233 
18234  if(InFile.is_open())
18235  {
18237  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float after v2.2.0
18238  {
18239  InFile.close();
18240  Utilities->CallLogPop(1240);
18241  return(false);
18242  }
18243  if(!CheckInterface(0, InFile))
18244  {
18245  InFile.close();
18246  Utilities->CallLogPop(1241);
18247  return(false);
18248  }
18249  // check track elements
18250  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
18251  {
18252  InFile.close();
18253  Utilities->CallLogPop(1242);
18254  return(false);
18255  }
18256  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
18257  {
18258  InFile.close();
18259  Utilities->CallLogPop(1243);
18260  return(false);
18261  }
18262  if(InFile.fail())
18263  {
18264  InFile.close();
18265  Utilities->CallLogPop(1244);
18266  return(false);
18267  }
18268  // check text elements
18269  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
18270  {
18271  InFile.close();
18272  Utilities->CallLogPop(1245);
18273  return(false);
18274  }
18275  if(!TextHandler->CheckTextElementsInFile(1, InFile))
18276  {
18277  InFile.close();
18278  Utilities->CallLogPop(1246);
18279  return(false);
18280  }
18281  if(InFile.fail())
18282  {
18283  InFile.close();
18284  Utilities->CallLogPop(1247);
18285  return(false);
18286  }
18287  // check PrefDir elements
18288  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
18289  {
18290  InFile.close();
18291  Utilities->CallLogPop(1248);
18292  return(false);
18293  }
18294  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
18295  {
18296  InFile.close();
18297  Utilities->CallLogPop(1249);
18298  return(false);
18299  }
18300  if(InFile.fail())
18301  {
18302  InFile.close();
18303  Utilities->CallLogPop(1250);
18304  return(false);
18305  }
18306  // check graphics
18307  if(GraphicsFollow)
18308  {
18309  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
18310  {
18311  InFile.close();
18312  Utilities->CallLogPop(2187);
18313  return(false);
18314  }
18315  if(InFile.fail())
18316  {
18317  InFile.close();
18318  Utilities->CallLogPop(2188);
18319  return(false);
18320  }
18321  }
18322  // check routes
18323  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
18324  {
18325  InFile.close();
18326  Utilities->CallLogPop(1251);
18327  return(false);
18328  }
18329  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
18330  {
18331  InFile.close();
18332  Utilities->CallLogPop(1252);
18333  return(false);
18334  }
18335  if(InFile.fail())
18336  {
18337  InFile.close();
18338  Utilities->CallLogPop(1253);
18339  return(false);
18340  }
18341  // check LockedRoutes
18342  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
18343  {
18344  InFile.close();
18345  Utilities->CallLogPop(1254);
18346  return(false);
18347  }
18348  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
18349  {
18350  InFile.close();
18351  Utilities->CallLogPop(1255);
18352  return(false);
18353  }
18354  if(InFile.fail())
18355  {
18356  InFile.close();
18357  Utilities->CallLogPop(1256);
18358  return(false);
18359  }
18360  // check ContinuationAutoSigs
18361  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
18362  {
18363  InFile.close();
18364  Utilities->CallLogPop(1257);
18365  return(false);
18366  }
18368  {
18369  InFile.close();
18370  Utilities->CallLogPop(1258);
18371  return(false);
18372  }
18373  if(InFile.fail())
18374  {
18375  InFile.close();
18376  Utilities->CallLogPop(1259);
18377  return(false);
18378  }
18379  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
18380  AnsiString TempString = Utilities->LoadFileString(InFile);
18381  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
18382  {
18383  InFile.close();
18384  Utilities->CallLogPop(1964);
18385  return(false);
18386  }
18387  if(TempString == "***BarriersDownVector***")
18388  {
18389  if(!Track->CheckActiveLCVector(0, InFile))
18390  {
18391  InFile.close();
18392  Utilities->CallLogPop(1965);
18393  return(false);
18394  }
18395  if(InFile.fail())
18396  {
18397  InFile.close();
18398  Utilities->CallLogPop(1966);
18399  return(false);
18400  }
18401  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
18402  {
18403  InFile.close();
18404  Utilities->CallLogPop(1260);
18405  return(false);
18406  }
18407  }
18408  // check timetable (marker string already checked immediately above)
18409  if(!CheckTimetableFromSessionFile(0, InFile))
18410  {
18411  InFile.close();
18412  Utilities->CallLogPop(1261);
18413  return(false);
18414  }
18415  if(InFile.fail())
18416  {
18417  InFile.close();
18418  Utilities->CallLogPop(1262);
18419  return(false);
18420  }
18421  }
18422  else
18423  {
18424  InFile.close();
18425  ShowMessage("Session file failed to open - reason not known, unable to load session.");
18426  Utilities->CallLogPop(1263);
18427  return(false);
18428  }
18429 // now ready for the 2nd pass for timetable loading and checking
18430  InFile.close();
18431  InFile.open(FileName.c_str());
18432  if(InFile.is_open())
18433  {
18435  {
18436  InFile.close();
18437  Utilities->CallLogPop(1264);
18438  return(false);
18439  }
18440  if(!CheckInterface(1, InFile))
18441  {
18442  InFile.close();
18443  Utilities->CallLogPop(1265);
18444  return(false);
18445  }
18446  // load track elements
18447  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
18448  {
18449  InFile.close();
18450  Utilities->CallLogPop(1266);
18451  return(false);
18452  }
18453  bool GraphicsFollow = false;
18454  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
18455  if(InFile.fail())
18456  {
18457  InFile.close();
18458  Utilities->CallLogPop(1267);
18459  return(false);
18460  }
18461  // check text elements
18462  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
18463  {
18464  InFile.close();
18465  Utilities->CallLogPop(1268);
18466  return(false);
18467  }
18468  if(!TextHandler->CheckTextElementsInFile(2, InFile))
18469  {
18470  InFile.close();
18471  Utilities->CallLogPop(1269);
18472  return(false);
18473  }
18474  if(InFile.fail())
18475  {
18476  InFile.close();
18477  Utilities->CallLogPop(1270);
18478  return(false);
18479  }
18480  // check PrefDir elements
18481  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
18482  {
18483  InFile.close();
18484  Utilities->CallLogPop(1271);
18485  return(false);
18486  }
18487  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
18488  {
18489  InFile.close();
18490  Utilities->CallLogPop(1272);
18491  return(false);
18492  }
18493  if(InFile.fail())
18494  {
18495  InFile.close();
18496  Utilities->CallLogPop(1273);
18497  return(false);
18498  }
18499  // check graphics
18500  if(GraphicsFollow)
18501  {
18502  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
18503  {
18504  InFile.close();
18505  Utilities->CallLogPop(2189);
18506  return(false);
18507  }
18508  if(InFile.fail())
18509  {
18510  InFile.close();
18511  Utilities->CallLogPop(2190);
18512  return(false);
18513  }
18514  }
18515  // check routes
18516  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
18517  {
18518  InFile.close();
18519  Utilities->CallLogPop(1274);
18520  return(false);
18521  }
18522  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
18523  {
18524  InFile.close();
18525  Utilities->CallLogPop(1275);
18526  return(false);
18527  }
18528  if(InFile.fail())
18529  {
18530  InFile.close();
18531  Utilities->CallLogPop(1276);
18532  return(false);
18533  }
18534  // check LockedRoutes
18535  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
18536  {
18537  InFile.close();
18538  Utilities->CallLogPop(1277);
18539  return(false);
18540  }
18541  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
18542  {
18543  InFile.close();
18544  Utilities->CallLogPop(1278);
18545  return(false);
18546  }
18547  if(InFile.fail())
18548  {
18549  InFile.close();
18550  Utilities->CallLogPop(1279);
18551  return(false);
18552  }
18553  // check ContinuationAutoSigs
18554  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
18555  {
18556  InFile.close();
18557  Utilities->CallLogPop(1280);
18558  return(false);
18559  }
18561  {
18562  InFile.close();
18563  Utilities->CallLogPop(1281);
18564  return(false);
18565  }
18566  if(InFile.fail())
18567  {
18568  InFile.close();
18569  Utilities->CallLogPop(1282);
18570  return(false);
18571  }
18572  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
18573  AnsiString TempString = Utilities->LoadFileString(InFile);
18574  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
18575  {
18576  InFile.close();
18577  Utilities->CallLogPop(1967);
18578  return(false);
18579  }
18580  if(TempString == "***BarriersDownVector***")
18581  {
18582  if(!Track->CheckActiveLCVector(0, InFile))
18583  {
18584  InFile.close();
18585  Utilities->CallLogPop(1968);
18586  return(false);
18587  }
18588  if(InFile.fail())
18589  {
18590  InFile.close();
18591  Utilities->CallLogPop(1969);
18592  return(false);
18593  }
18594  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
18595  {
18596  InFile.close();
18597  Utilities->CallLogPop(1283);
18598  return(false);
18599  }
18600  }
18601  // check timetable (marker string already checked)
18602  if(!LoadTimetableFromSessionFile(1, InFile))
18603  {
18604  InFile.close();
18605  Utilities->CallLogPop(1284);
18606  return(false);
18607  }
18608  if(InFile.fail())
18609  {
18610  InFile.close();
18611  Utilities->CallLogPop(1285);
18612  return(false);
18613  }
18614  // check timetable clock
18615  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
18616  {
18617  InFile.close();
18618  Utilities->CallLogPop(1286);
18619  return(false);
18620  }
18621  if(!Utilities->CheckFileDouble(InFile))
18622  {
18623  InFile.close();
18624  Utilities->CallLogPop(1287);
18625  return(false);
18626  }
18627  // check trains
18628  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
18629  {
18630  InFile.close();
18631  Utilities->CallLogPop(1288);
18632  return(false);
18633  }
18634  if(!TrainController->CheckSessionTrains(0, InFile))
18635  {
18636  InFile.close();
18637  Utilities->CallLogPop(1289);
18638  return(false);
18639  }
18640  if(InFile.fail())
18641  {
18642  InFile.close();
18643  Utilities->CallLogPop(1290);
18644  return(false);
18645  }
18646  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
18647  {
18648  InFile.close();
18649  Utilities->CallLogPop(1291);
18650  return(false);
18651  }
18652  if(!CheckPerformanceFile(0, InFile))
18653  {
18654  InFile.close();
18655  Utilities->CallLogPop(1292);
18656  return(false);
18657  }
18658  char TempChar;
18659  InFile.get(TempChar);
18660  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
18661  {
18662  InFile.get(TempChar);
18663  }
18664  if(!InFile.eof()) // additional checks needed
18665  {
18666  if(!Utilities->CheckFileString(InFile))
18667  {
18668  InFile.close();
18669  Utilities->CallLogPop(2198);
18670  return(false);
18671  }
18672  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
18673  {
18674  InFile.close();
18675  Utilities->CallLogPop(2199);
18676  return(false);
18677  }
18678  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
18679  {
18680  InFile.close();
18681  Utilities->CallLogPop(2200);
18682  return(false);
18683  }
18684  // now check any failed trains along with their OriginalPowerAtRail values
18685  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
18686  int IDVal;
18687  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
18688  {
18689  InFile.close();
18690  Utilities->CallLogPop(2201);
18691  return(false);
18692  }
18693  double PowerDouble;
18694  while(IDVal != -1)
18695  {
18696  Utilities->CheckFileDouble(InFile); // original power
18697  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
18698  {
18699  InFile.close();
18700  Utilities->CallLogPop(2202);
18701  return(false);
18702  }
18703  }
18704  }
18705  InFile.close();
18706  }
18707  else
18708  {
18709  InFile.close();
18710  Utilities->CallLogPop(1293);
18711  return(false);
18712  }
18713  Utilities->CallLogPop(1294);
18714  return(true);
18715 }
18716 
18717 // ---------------------------------------------------------------------------
18718 
18719 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
18720 // Note that the file integrity has already been checked using CheckPerformanceFile
18721 {
18722  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
18723  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
18724  char *Buffer = new char[1000];
18725  char TempChar;
18726 
18727  InFile.get(TempChar); // '\n'
18728  InFile.getline(Buffer, 1000);
18729  TempString = AnsiString(Buffer);
18730  while(TempString != "***End of performance file***")
18731  {
18732  PerformanceLogBox->Lines->Add(TempString);
18733  Utilities->PerformanceFile << TempString.c_str() << '\n';
18734  InFile.getline(Buffer, 1000);
18735  TempString = AnsiString(Buffer);
18736  }
18737  delete[]Buffer;
18738  Utilities->CallLogPop(1295);
18739 }
18740 
18741 // ---------------------------------------------------------------------------
18742 
18743 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
18744 {
18745  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
18746  AnsiString TempString = "";
18747  char TempChar;
18748 
18749  InFile.get(TempChar);
18750  if(TempChar != '\n')
18751  {
18752  Utilities->CallLogPop(1296);
18753  return(false);
18754  }
18755  if(!Utilities->CheckAndReadFileString(InFile, TempString))
18756  {
18757  Utilities->CallLogPop(1297);
18758  return(false);
18759  }
18760  while(TempString != "***End of performance file***")
18761  {
18762  if(!Utilities->CheckAndReadFileString(InFile, TempString))
18763  {
18764  Utilities->CallLogPop(1298);
18765  return(false);
18766  }
18767  }
18768  Utilities->CallLogPop(1299);
18769  return(true);
18770 }
18771 
18772 // ---------------------------------------------------------------------------
18773 
18774 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
18775 {
18776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
18777  AnsiString Text = PerformanceLogBox->Text;
18778 
18779  while(Text != "")
18780  {
18781  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
18782  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
18783  {
18784  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
18785  }
18786  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
18787  while((Text.Length() > 0) && Text[1] < ' ')
18788  {
18789  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
18790  }
18791  OutFile << OneLine.c_str() << '\n';
18792  }
18793  Utilities->CallLogPop(1300);
18794 }
18795 
18796 // ---------------------------------------------------------------------------
18797 
18799 {
18800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
18801  if(EveryPrefDir->PrefDirSize() > 0)
18802  {
18803  if(AutoSigsFlag)
18804  {
18805  AutoSigsButton->Enabled = false;
18806  SigPrefConsecButton->Enabled = true;
18807  SigPrefNonConsecButton->Enabled = true;
18808  UnrestrictedButton->Enabled = true;
18809  InfoPanel->Visible = true;
18810  if(Level2OperMode == PreStart)
18811  {
18812  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
18813  }
18814  else
18815  {
18816  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
18817  }
18818  InfoCaptionStore = InfoPanel->Caption;
18819  }
18820  else if(PreferredRoute & ConsecSignalsRoute) // added at v2.7.0, was just ConsecSignalsRoute
18821  {
18822  AutoSigsButton->Enabled = true;
18823  SigPrefConsecButton->Enabled = false;
18824  SigPrefNonConsecButton->Enabled = true;
18825  UnrestrictedButton->Enabled = true;
18826  InfoPanel->Visible = true;
18827  if(Level2OperMode == PreStart)
18828  {
18829  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
18830  }
18831  else
18832  {
18833  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
18834  }
18835  InfoCaptionStore = InfoPanel->Caption;
18836  }
18837  else if(PreferredRoute&!ConsecSignalsRoute) // added at v2.7.0
18838  {
18839  AutoSigsButton->Enabled = true;
18840  SigPrefConsecButton->Enabled = true;
18841  SigPrefNonConsecButton->Enabled = false;
18842  UnrestrictedButton->Enabled = true;
18843  InfoPanel->Visible = true;
18844  if(Level2OperMode == PreStart)
18845  {
18846  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
18847  }
18848  else
18849  {
18850  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
18851  }
18852  InfoCaptionStore = InfoPanel->Caption;
18853  }
18854  else
18855  {
18856  AutoSigsButton->Enabled = true;
18857  SigPrefConsecButton->Enabled = true;
18858  SigPrefNonConsecButton->Enabled = true;
18859  UnrestrictedButton->Enabled = false;
18860  InfoPanel->Visible = true;
18861  if(Level2OperMode == PreStart)
18862  {
18863  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
18864  }
18865  else
18866  {
18867  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
18868  }
18869  InfoCaptionStore = InfoPanel->Caption;
18870  }
18871  }
18872  else
18873  {
18874  AutoSigsButton->Enabled = false;
18875  SigPrefConsecButton->Enabled = false;
18876  SigPrefNonConsecButton->Enabled = false;
18877  UnrestrictedButton->Enabled = false;
18878  InfoPanel->Visible = true;
18879  if(Level2OperMode == PreStart)
18880  {
18881  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
18882  }
18883  else
18884  {
18885  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
18886  }
18887  InfoCaptionStore = InfoPanel->Caption;
18888  }
18890  {
18891  RouteCancelButton->Enabled = true;
18892  }
18893  else
18894  {
18895  RouteCancelButton->Enabled = false;
18896  }
18898  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
18901  Utilities->CallLogPop(1301);
18902 }
18903 
18904 // ---------------------------------------------------------------------------
18905 
18907 {
18908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
18909  if(Display->ZoomOutFlag)
18910  {
18911  InfoPanel->Visible = true;
18912  InfoPanel->Caption = "Left click screen to zoom in at that position";
18913  }
18914  else if(Level2OperMode == Paused)
18915  {
18916  InfoPanel->Visible = true;
18917  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
18918  }
18919 // otherwise do nothing
18920  Utilities->CallLogPop(1302);
18921 }
18922 
18923 // ---------------------------------------------------------------------------
18924 
18926 {
18927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
18928  RouteCancelButton->Enabled = false;
18929  AutoSigsButton->Enabled = false;
18930  SigPrefConsecButton->Enabled = false;
18931  SigPrefNonConsecButton->Enabled = false;
18932  UnrestrictedButton->Enabled = false;
18933  Utilities->CallLogPop(1303);
18934 }
18935 
18936 // ---------------------------------------------------------------------------
18937 
18939 // no need for call logging as already failed
18940 {
18941 /*
18942  In order to reload as a session file:
18943 
18944  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
18945  strip out:-
18946 
18947  [since adding user graphics after prefdirs need to take this into account]
18948 
18949  up to but excluding ***Interface***
18950  from & including ***ConstructPrefDir PrefDirVector***
18951  to but excluding ***PrefDirs***
18952  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
18953  from & including ***ConstructRoute PrefDirVector***
18954  to but excluding ***Routes***
18955  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
18956  from & including ***No editing timetable*** or ***Editing timetable - [title]***
18957  to but excluding ***TimetableClock***
18958  and save as a .ssn file.
18959 
18960  In order to load as a railway file:
18961 
18962  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
18963 
18964  note or copy the version information at the top of the file
18965  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
18966  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
18967  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
18968  the next line after the two insertions should contain the number of active elements.
18969  strip out ***Text*** including the \0
18970  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
18971  strip out ***UserGraphics*** including the \0
18972  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
18973  rename as .dev or .rly file
18974 
18975  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
18976  'Operate' then 'Exit operation'.
18977 */
18978 
18979 /*
18980  In order to extract a timetable:
18981 
18982  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
18983 
18984  set wordwrap to window on
18985  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
18986  ensure any text before start time ends with /0, otherwise don't need the \0
18987  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
18988  save as a .ttb file
18989 */
18990 
18991  Screen->Cursor = TCursor(-11); // Hourglass;
18992  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
18993  std::ofstream ErrorFile(ErrorFileStr.c_str());
18994 
18995  if(!(ErrorFile.fail()))
18996  {
18997 // save mouse position relative to mainscreen
18998  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
18999  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
19000  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
19001  Utilities->SaveFileString(ErrorFile, MouseStr);
19002  Utilities->SaveFileInt(ErrorFile, MissedTicks);
19003  Utilities->SaveFileInt(ErrorFile, TotalTicks);
19004 
19005 // save call stack
19006  Utilities->SaveFileString(ErrorFile, "***Call stack***");
19007  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
19008  {
19009  AnsiString Item = Utilities->CallLog.at(x);
19010  ErrorFile << Item.c_str() << '\n';
19011  }
19012 // save event log
19013  Utilities->SaveFileString(ErrorFile, "***Event log***");
19014  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
19015  {
19016  AnsiString Item = Utilities->EventLog.at(x);
19017  ErrorFile << Item.c_str() << '\n';
19018  }
19019 // save interface
19020  Utilities->SaveFileString(ErrorFile, "***Interface***");
19021  SaveInterface(1, ErrorFile);
19022 // save track elements
19023  Utilities->SaveFileString(ErrorFile, "***Track***");
19024  if(Track->UserGraphicVector.empty())
19025  {
19026  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
19027  }
19028  else
19029  {
19030  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
19031  }
19032 // save text elements
19033  Utilities->SaveFileString(ErrorFile, "***Text***");
19034  TextHandler->SaveText(3, ErrorFile);
19035 // save ConstructPrefDir PrefDirVector elements
19036  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
19037  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
19038 // save ConstructPrefDir SearchVector elements
19039  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
19040  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
19041 // save EveryPrefDir elements
19042  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
19043  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
19044  if(!Track->UserGraphicVector.empty())
19045  {
19046  // save user graphics
19047  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
19048  Track->SaveUserGraphics(3, ErrorFile);
19049  }
19050 // save ConstructRoute PrefDirVector
19051  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
19052  ConstructRoute->SavePrefDirVector(4, ErrorFile);
19053 // save ConstructRoute SearchVector
19054  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
19055  ConstructRoute->SaveSearchVector(1, ErrorFile);
19056 // save AllRoutes
19057  Utilities->SaveFileString(ErrorFile, "***Routes***");
19058  AllRoutes->SaveRoutes(1, ErrorFile);
19059 // save LockedRoutes
19060  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
19062 // save ContinuationAutoSigEntries
19063  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
19065 // save BarriersDownVector
19066  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
19067  Track->SaveSessionBarriersDownVector(1, ErrorFile);
19068 // save ChangingLCVector
19069  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
19070  Track->SaveChangingLCVector(0, ErrorFile);
19071 // save loaded timetable
19072  if(TimetableTitle == "")
19073  {
19074  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
19075  }
19076  else
19077  {
19078  Utilities->SaveFileString(ErrorFile, "***Timetable***");
19079  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
19080  {
19081  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
19082  }
19083  }
19084 // save editing timetable
19085  if(CreateEditTTTitle == "")
19086  {
19087  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
19088  }
19089  else
19090  {
19091  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
19092  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
19093  {
19094  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
19095  }
19096  }
19097 // save TimetableClock
19098  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
19099  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
19100 // save trains
19101  Utilities->SaveFileString(ErrorFile, "***Trains***");
19102  TrainController->SaveSessionTrains(1, ErrorFile);
19103 // save performance file
19104  Utilities->SaveFileString(ErrorFile, "***Performance file***");
19105  SavePerformanceFile(1, ErrorFile);
19106  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
19107 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
19108  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
19111  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
19112  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19113  {
19115  {
19118  }
19119  }
19120  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
19121  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
19122 // end of v2.4.1 addition
19123 
19124 // addition at v2.8.0 in case of clipboard errors
19125  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Height); // extras for new clipboard functions
19126  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Width);
19127  Utilities->SaveFileInt(ErrorFile, SelectBitmapHLoc); // paste location
19128  Utilities->SaveFileInt(ErrorFile, SelectBitmapVLoc);
19129  Utilities->SaveFileInt(ErrorFile, SelectRect.left); // original selection location
19130  Utilities->SaveFileInt(ErrorFile, SelectRect.top);
19131  Utilities->SaveFileInt(ErrorFile, SelectRect.right);
19132  Utilities->SaveFileInt(ErrorFile, SelectRect.bottom);
19133  Utilities->SaveFileString(ErrorFile, "End of file at v2.8.0");
19134 // end of 2.8.0 addition
19135  ErrorFile.close();
19136  }
19137  else
19138  {
19139  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
19140  }
19141  Screen->Cursor = TCursor(-2); // Arrow
19142 }
19143 
19144 // ---------------------------------------------------------------------------
19145 
19146 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
19147 // the .ttb section is delimited by '\n' followed by "***End***"
19148 // first create a .ttb file in the working folder exactly like the original
19149 
19150 // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
19151 // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
19152 {
19153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
19154  if((TempTTFileName != "") && FileExists(TempTTFileName))
19155  {
19156  DeleteFile(TempTTFileName);
19157  }
19158  int TempTTFileNumber = 0;
19159 
19160  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
19161  {
19162  TempTTFileNumber++;
19163  }
19164  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
19165  int InHandle = FileOpen(InFileName, fmOpenRead);
19166  int Count = 0;
19167 
19168  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
19169  {
19170  InHandle = FileOpen(InFileName, fmOpenRead);
19171  Count++;
19172  Delay(2, 50); // 50mSec delay between tries
19173  if(Count > 10)
19174  {
19175  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
19176  Utilities->CallLogPop(1400);
19177  return;
19178  }
19179  }
19180  int OutHandle = FileCreate(TempTTFileName);
19181 
19182  Count = 0;
19183  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
19184  {
19185  OutHandle = FileCreate(TempTTFileName);
19186  Count++;
19187  Delay(3, 50); // 50mSec delay between tries
19188  if(Count > 10)
19189  {
19190  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
19191  FileClose(InHandle);
19192  Utilities->CallLogPop(1401);
19193  return;
19194  }
19195  }
19196  int CountIn, CountOut;
19197  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
19198 
19199  while(true)
19200  {
19201  CountIn = FileRead(InHandle, Buffer, 10000);
19202  CountOut = FileWrite(OutHandle, Buffer, CountIn);
19203  if(CountOut != CountIn)
19204  {
19205  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
19206  delete[]Buffer;
19207  FileClose(InHandle);
19208  FileClose(OutHandle);
19209  Utilities->CallLogPop(1402);
19210  return;
19211  }
19212  if(CountIn < 10000)
19213  {
19214  break;
19215  }
19216  }
19217  delete[]Buffer;
19218  FileClose(InHandle);
19219  FileClose(OutHandle);
19220  Utilities->CallLogPop(1403);
19221 }
19222 
19223 // ---------------------------------------------------------------------------
19224 
19225 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
19226 /*
19227  Rules: Platforms are fixed length elements of 100m and aren't changed - no, see note below. Variable length elements can't be less than 20m.
19228  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
19229 
19230  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
19231  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
19232  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
19233  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
19234  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
19235  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
19236  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
19237  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
19238  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
19239  the next XLinkPos for each succeeding element.
19240  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
19241  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
19242  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
19243  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
19244  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
19245  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
19246  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
19247  been set), an error message is given.
19248 */
19249 
19250 {
19251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
19252  bool FoundFlag;
19253 
19254 // ResetDistanceElements(4);
19255  if(ConstructPrefDir->PrefDirSize() == 0)
19256  {
19257  Utilities->CallLogPop(608);
19258  return;
19259  }
19260 // must have PrefDir size of at least 2
19261 
19262 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
19263 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
19264  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
19265  bool NamedLocPresent = false;
19266 
19267  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
19268  {
19269  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
19270  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
19271  if(!FoundFlag)
19272  {
19273  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
19274  }
19275  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
19276  {
19277  VarElements++;
19278  }
19279  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
19280  {
19281  VarElements++; // added in v2.4.0 for no fixed elements
19282  NamedLocPresent = true;
19283 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
19284  }
19285  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
19286  {
19287  if(SpeedLimit != -1)
19288  {
19289  TE.SpeedLimit01 = SpeedLimit;
19290  }
19291  }
19292  else
19293  {
19294  if(SpeedLimit != -1)
19295  {
19296  TE.SpeedLimit23 = SpeedLimit;
19297  }
19298  }
19299  }
19300  if(Distance == -1) // can't return before this as need to set speed limits
19301  {
19302  Utilities->CallLogPop(612);
19303  return;
19304  }
19305  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
19306  {
19307  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
19308  }
19309  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
19310  {
19311  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
19312  }
19313 /* if(NamedLocPresent) as was
19314  {
19315  ShowMessage("Named location lengths won't be changed");
19316  }
19317 */
19318 
19319  if((VarElements * 20) > Distance) // removed '+ FixedLength'
19320  {
19321  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
19322  Distance = (VarElements * 20); // removed '+ FixedLength'
19323  }
19324  if(VarElements == 0)
19325  {
19326 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
19327  ShowMessage("No elements selected"); // probably don't need this but include for safety
19328  Utilities->CallLogPop(613);
19329  return;
19330  }
19331 // second pass, set variable lengths
19332  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
19333 
19334  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
19335  {
19336  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
19337  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
19338 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
19339 // {
19340  if(NextLength < 20)
19341  {
19342  NextLength = 20; // added for safety
19343  }
19344  if(TE.TrackType == Points)
19345  {
19346  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
19347  {
19348  TE.Length01 = NextLength;
19349  }
19350  else
19351  {
19352  TE.Length23 = NextLength;
19353  }
19354  }
19355  else
19356  {
19357  if(PrefDirElement.GetELinkPos() < 2)
19358  {
19359  TE.Length01 = NextLength;
19360  }
19361  else
19362  {
19363  TE.Length23 = NextLength;
19364  }
19365  }
19366  RemainingDistance -= NextLength;
19367  RemainingVarElements--;
19368  if(RemainingVarElements > 0)
19369  {
19370  NextLength = RemainingDistance / RemainingVarElements;
19371  }
19372  else
19373  {
19374  NextLength = 20;
19375  }
19376 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
19377  if((RemainingDistance == 0) && (RemainingVarElements != 0))
19378  {
19379  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
19380  }
19381  if((RemainingDistance != 0) && (RemainingVarElements == 0))
19382  {
19383  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
19384  }
19385 */
19386 // }
19387  }
19388  Utilities->CallLogPop(614);
19389 }
19390 
19391 // ---------------------------------------------------------------------------
19392 
19394 {
19395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
19397  {
19398  ShowMessage("Nothing to save!");
19399  }
19400  else
19401  {
19402  if(Track->IsReadyForOperation(false))
19403  {
19404  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
19405  }
19406  else
19407  {
19408  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
19409  }
19410  if(SaveRailwayDialog->Execute())
19411  {
19412  if(SaveRailwayDialog->InitialDir != TPath::GetDirectoryName(SaveRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
19413  {
19414  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
19415  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
19416  }
19417  Screen->Cursor = TCursor(-11); // Hourglass;
19418  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
19419  AnsiString Extension = "";
19420  if(SaveRailwayDialog->FileName.Length() > 2)
19421  {
19422  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
19423  }
19424  if((Extension == "DEV") || (Track->IsReadyForOperation(true) && (Extension == "RLY"))) // give duplicated location name message if appropriate
19425  {
19426  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
19427  if(!(VecFile.fail()))
19428  {
19432  // save track elements
19433  if(Track->UserGraphicVector.empty())
19434  {
19435  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
19436  }
19437  else
19438  {
19439  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
19440  }
19441  // save text elements
19442  TextHandler->SaveText(1, VecFile);
19443  // save PrefDir elements
19444  EveryPrefDir->SavePrefDirVector(1, VecFile);
19445  if(!Track->UserGraphicVector.empty())
19446  {
19447  // save user graphics
19448  Track->SaveUserGraphics(4, VecFile);
19449  }
19450  VecFile.close();
19451  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
19452  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
19453  {
19454  char LastChar = SavedFileName[SavedFileName.Length()];
19455  if((LastChar == 'y') || (LastChar == 'Y'))
19456  {
19457  RlyFile = true;
19458  }
19459  else
19460  {
19461  RlyFile = false;
19462  }
19463  }
19464  else
19465  {
19466  RlyFile = false;
19467  }
19468  FileChangedFlag = false;
19469  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
19470  {
19471  if(SaveRailwayDialog->FileName[x] == '\\')
19472  {
19473  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
19474  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
19475  SetCaption(7);
19476  break;
19477  }
19478  }
19479  Level1Mode = BaseMode;
19480  SetLevel1Mode(13); // to disable the save option
19481  } // if(!(VecFile.fail()))
19482  else
19483  {
19484  ShowMessage("File open failed prior to save");
19485  }
19486  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
19487  else
19488  {
19489  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
19490  }
19491  Screen->Cursor = TCursor(-2); // Arrow
19492  } // if(SaveRailwayDialog->Execute())
19493 
19494  }
19495  Utilities->CallLogPop(1546);
19496 }
19497 
19498 // ---------------------------------------------------------------------------
19499 
19501 {
19502  // no need for caller or log as only setting values
19503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackModeEditMenu");
19504  CutMenuItem->Visible = true;
19505  CopyMenuItem->Visible = true;
19506  FlipMenuItem->Visible = true;
19507  MirrorMenuItem->Visible = true;
19508  RotRightMenuItem->Visible = true;
19509  RotLeftMenuItem->Visible = true;
19510  RotateMenuItem->Visible = true;
19511  PasteMenuItem->Visible = true;
19512  DeleteMenuItem->Visible = true;
19513  SelectLengthsMenuItem->Visible = true;
19514  ReselectMenuItem->Visible = true;
19515 // Application->MessageBox(L"Running SetTrackModeEditMenu", L"Message", MB_OK); //debug check
19516  CutMenuItem->Enabled = false;
19517  CopyMenuItem->Enabled = false;
19518  FlipMenuItem->Enabled = false;
19519  MirrorMenuItem->Enabled = false;
19520  RotRightMenuItem->Enabled = false;
19521  RotLeftMenuItem->Enabled = false;
19522  RotateMenuItem->Enabled = false;
19523  PasteMenuItem->Enabled = false;
19524  EditMenu->Enabled = false;
19525  System::WideChar ValidityBuffer[14];
19526  Clipboard()->GetTextBuf(ValidityBuffer, 14);
19527  ClpBrdValid = AnsiString(ValidityBuffer);
19528  Clipboard()->Close();
19529 
19530 // new section for 2.8.0 in case have valid clipboard from another application
19531  if(!SelectionValid)
19532  {
19533  if(ClpBrdValid == "RlyClpBrdCopy")
19534  {
19535  PasteMenuItem->Enabled = true;
19536  if(Level1Mode == TrackMode)
19537  {
19538  EditMenu->Enabled = true;
19539  }
19540  CopySelected = true;
19541  Track->CopyFlag = true;
19542 // Level1Mode = TrackMode;
19543  }
19544  else if(ClpBrdValid == "RlyClpBrd_Cut")
19545  {
19546  PasteMenuItem->Enabled = true;
19547  if(Level1Mode == TrackMode)
19548  {
19549  EditMenu->Enabled = true;
19550  }
19551  CopySelected = false;
19552  Track->CopyFlag = false;
19553 // Level1Mode = TrackMode;
19554  }
19555  }
19556 // end of new section
19557 
19558 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
19559  ClpBrdValid = "";
19560  DeleteMenuItem->Enabled = false;
19561  SelectLengthsMenuItem->Enabled = false;
19562  if(SelectionValid)
19563  {
19564  ReselectMenuItem->Enabled = true;
19565  }
19566  else
19567  {
19568  ReselectMenuItem->Enabled = false;
19569  }
19570  SelectBiDirPrefDirsMenuItem->Visible = false;
19571  CancelSelectionMenuItem->Enabled = true;
19572  SelectMenuItem->Enabled = true;
19573 
19574  if(NoRailway())
19575  {
19576  SelectMenuItem->Enabled = false;
19577  }
19578  else if(Level1Mode == TrackMode)
19579  {
19580  EditMenu->Enabled = true;
19581  }
19582  Utilities->CallLogPop(2273);
19583 }
19584 
19585 // ---------------------------------------------------------------------------
19586 
19588 {
19589  // no need for caller or log as only setting values
19590  EditMenu->Enabled = true;
19591 
19592  CutMenuItem->Visible = false;
19593  CopyMenuItem->Visible = false;
19594  FlipMenuItem->Visible = false;
19595  MirrorMenuItem->Visible = false;
19596  RotRightMenuItem->Visible = false;
19597  RotLeftMenuItem->Visible = false;
19598  RotateMenuItem->Visible = false;
19599  PasteMenuItem->Visible = false;
19600 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
19601  DeleteMenuItem->Visible = false;
19602  SelectLengthsMenuItem->Visible = false;
19603  ReselectMenuItem->Visible = false;
19604 
19605  SelectBiDirPrefDirsMenuItem->Visible = true;
19606  SelectBiDirPrefDirsMenuItem->Enabled = false;
19607  CancelSelectionMenuItem->Enabled = true;
19608  SelectMenuItem->Enabled = true;
19609 }
19610 
19611 // ---------------------------------------------------------------------------
19612 
19614 {
19615  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
19616 }
19617 
19618 // ---------------------------------------------------------------------------
19619 
19621 {
19622  SelectRect.left = 0;
19623  SelectRect.right = 0;
19624  SelectRect.top = 0;
19625  SelectRect.bottom = 0;
19626 }
19627 
19628 // ---------------------------------------------------------------------------
19629 
19630 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
19631 {
19632  // return position of erased name in HPos & VPos, return true for found & erased
19633  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
19634  bool TextFound = false;
19635 
19636 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
19637 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
19638  {
19639  if(TextHandler->TextErase(4, HPos, VPos, Name))
19640  {
19641  ;
19642  } // condition not used
19643 
19644  TextFound = true;
19645  }
19646  Utilities->CallLogPop(1956);
19647  return(TextFound);
19648 }
19649 
19650 // ---------------------------------------------------------------------------
19651 
19652 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
19653 {
19654  if(Name == "")
19655  {
19656  return;
19657  }
19658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
19659  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
19660  int VPosHi, VPosLo, TextPosHi, TextPosLo;
19661  TFont *Font = Display->GetFont();
19662 
19663  if(!UseEnteredPosition)
19664  {
19665  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
19666  {
19667  Utilities->CallLogPop(1561);
19668  return;
19669  }
19670  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
19671  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
19672  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
19673  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
19674  int ScreenPosLo = Display->DisplayOffsetV * 16;
19675  if(TextPosLo >= ScreenPosLo)
19676  {
19677  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
19678  }
19679  else if(TextPosHi < ScreenPosHi)
19680  {
19681  VPos = TextPosHi;
19682  }
19683  else
19684  {
19685  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
19686  }
19687  }
19688  TTextItem TI(HPos, VPos, Name, Font);
19689 
19690  TI.Font = Font; // may have been changed in constructor when returned as reference
19691  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
19692  Utilities->CallLogPop(1558);
19693 }
19694 
19695 // ---------------------------------------------------------------------------
19696 
19698 {
19699  try
19700  {
19701 /*
19702  ShowMessage(
19703  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
19704  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
19705  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
19706  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
19707  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
19708  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
19709  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
19710  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
19711  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
19712  "\nInterface->Left " + UnicodeString(Interface->Left) +
19713  "\nInterface->Top " + UnicodeString(Interface->Top) +
19714  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
19715  );
19716 */
19717 /*
19718  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
19719  {
19720  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
19721  {
19722  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
19723  }
19724  }
19725 */
19726 
19727 // throw Exception("Test error"); //generate an error file
19728 
19729 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
19730 
19731  }
19732  catch(const Exception &e)
19733  {
19734  ErrorLog(114, e.Message);
19735  }
19736 }
19737 
19738 // ---------------------------------------------------------------------------
19739 /*
19740  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
19741  {
19742  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
19743  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
19744  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
19745  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
19746  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
19747  Utilities->CallLogPop(**);
19748  }
19749 
19750  //---------------------------------------------------------------------------
19751 
19752  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
19753  {
19754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
19755  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
19756  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
19757  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
19758  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
19759  Utilities->CallLogPop(**);
19760  }
19761 */
19762 // ---------------------------------------------------------------------------
19763 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
19764 {
19765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
19774  Utilities->CallLogPop(1871);
19775 }
19776 
19777 // ---------------------------------------------------------------------------
19778 
19779 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
19780 {
19781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
19790  Utilities->CallLogPop(1872);
19791 }
19792 
19793 // ---------------------------------------------------------------------------
19794 
19795 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
19796 // limit it to 20 entries max
19797 {
19798  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
19800  {
19801  OAListBox->Clear();
19802  }
19804  // new at v2.2.0
19805  {
19806  Utilities->CallLogPop(2092);
19807  return;
19808  }
19809  AnsiString OpTimeToActDisplay;
19810  AnsiString OpTimeToActString;
19811  AnsiString HeadCode;
19812  float OpTimeToActFloat;
19813  TTrainController::THCandTrainPosParam HCandTrainPosParam;
19814 
19817  {
19818  if(OAListBox->Items->Count >= 20)
19819  {
19820  break;
19821  }
19822  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
19823  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
19824  HeadCode = HCandTrainPosParam.first;
19825  if(OpTimeToActFloat < 0.25) // 15 secs estimated
19826  {
19827  OpTimeToActString = "NOW";
19828  }
19829  else if(OpTimeToActFloat < 1)
19830  {
19831  OpTimeToActString = "<1";
19832  }
19833  else
19834  {
19835  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
19836  }
19837  if(OpTimeToActFloat < 60)
19838  {
19839  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
19840  OAListBox->Items->Add(OpTimeToActDisplay); // original
19841  }
19843  }
19844  Utilities->CallLogPop(2093);
19845 }
19846 
19847 // ---------------------------------------------------------------------------
19848 
19849 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
19850 {
19851  try
19852  {
19853  TrainController->LogEvent("LoadUserGraphic");
19854  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
19855  if(LoadUserGraphicDialog->Execute())
19856  {
19857  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
19858  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
19860  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
19861  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
19862  {
19863  UGME.first = SelectedGraphicFileName;
19864  TPicture *PicPtr = new TPicture;
19865  PicPtr->LoadFromFile(SelectedGraphicFileName);
19866  UGME.second = PicPtr;
19867  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
19868  {
19869  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
19870  }
19871  }
19873  SetLevel2TrackMode(65);
19874  }
19875  Utilities->CallLogPop(2191);
19876  }
19877  catch(const EInvalidGraphic &e)
19878  {
19879  ShowMessage(
19880  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
19881  }
19882  catch(const Exception &e)
19883  {
19884  ErrorLog(215, e.Message);
19885  }
19886 }
19887 
19888 // ---------------------------------------------------------------------------
19889 
19890 void TInterface::LoadClipboard(int Caller) // new at v2.8.0
19891 {
19892  try
19893  {
19894  TrainController->LogEvent("LoadClipboard");
19895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadClipboard");
19896 
19897  std::wstringstream wss; // used to hold all parameters prior to conversion to a string buffer
19898  if(CopySelected)
19899  {
19900  wss << "RlyClpBrdCopy\n";
19901  }
19902  else
19903  {
19904  wss << "RlyClpBrd_Cut\n";
19905  }
19906 // Load the active & inactive track vectors
19907  for(TTrack::TTrackVectorIterator TTVIt = Track->SelectVector.begin(); TTVIt < Track->SelectVector.end(); TTVIt++)
19908  {
19909  wss << TTVIt->SpeedTag;
19910  wss << '\n'; // inherited int - all FixedTrackPiece parameters implicit in this
19911  for(int AnsLen = 0; AnsLen <= TTVIt->ActiveTrackElementName.Length(); AnsLen++)
19912  {
19913  if((TTVIt->ActiveTrackElementName).c_str()[AnsLen] != '\0')
19914  {
19915  wss << (TTVIt->ActiveTrackElementName).c_str()[AnsLen];
19916  }
19917  else
19918  {
19919  wss << '\n';
19920  }
19921  }
19922  for(int AnsLen = 0; AnsLen <= TTVIt->ElementID.Length(); AnsLen++)
19923  {
19924  if((TTVIt->ElementID).c_str()[AnsLen] != '\0')
19925  {
19926  wss << (TTVIt->ElementID).c_str()[AnsLen];
19927  }
19928  else
19929  {
19930  wss << '\n';
19931  }
19932  }
19933  for(int AnsLen = 0; AnsLen <= TTVIt->LocationName.Length(); AnsLen++)
19934  {
19935  if((TTVIt->LocationName).c_str()[AnsLen] != '\0')
19936  {
19937  wss << (TTVIt->LocationName).c_str()[AnsLen];
19938  }
19939  else
19940  {
19941  wss << '\n';
19942  }
19943  }
19944  wss << TTVIt->CallingOnSet;
19945  wss << '\n';
19946  wss << TTVIt->LCPlotted;
19947  wss << '\n';
19948  wss << TTVIt->TempTrackMarker01;
19949  wss << '\n';
19950  wss << TTVIt->TempTrackMarker23;
19951  wss << '\n';
19952  wss << TTVIt->Attribute;
19953  wss << '\n'; // all ints from here except last which is an enum
19954  wss << TTVIt->Conn[0];
19955  wss << '\n';
19956  wss << TTVIt->Conn[1];
19957  wss << '\n';
19958  wss << TTVIt->Conn[2];
19959  wss << '\n';
19960  wss << TTVIt->Conn[3];
19961  wss << '\n';
19962  wss << TTVIt->ConnLinkPos[0];
19963  wss << '\n';
19964  wss << TTVIt->ConnLinkPos[1];
19965  wss << '\n';
19966  wss << TTVIt->ConnLinkPos[2];
19967  wss << '\n';
19968  wss << TTVIt->ConnLinkPos[3];
19969  wss << '\n';
19970  wss << TTVIt->HLoc;
19971  wss << '\n';
19972  wss << TTVIt->VLoc;
19973  wss << '\n';
19974  wss << TTVIt->Length01;
19975  wss << '\n';
19976  wss << TTVIt->Length23;
19977  wss << '\n';
19978  wss << TTVIt->SpeedLimit01;
19979  wss << '\n';
19980  wss << TTVIt->SpeedLimit23;
19981  wss << '\n';
19982  wss << TTVIt->StationEntryStopLinkPos1;
19983  wss << '\n';
19984  wss << TTVIt->StationEntryStopLinkPos2;
19985  wss << '\n';
19986  wss << TTVIt->TrainIDOnElement;
19987  wss << '\n';
19988  wss << TTVIt->TrainIDOnBridgeTrackPos01;
19989  wss << '\n';
19990  wss << TTVIt->TrainIDOnBridgeTrackPos23;
19991  wss << '\n';
19992  wss << int(TTVIt->SigAspect);
19993  wss << '\n'; // enum
19994  }
19995  wss << "$$$" << '\n'; // send track element end marker
19996 
19997 // Load the text vector
19998 
19999  for(TTextHandler::TTextVectorIterator TTVIt = TextHandler->SelectTextVector.begin(); TTVIt < TextHandler->SelectTextVector.end(); TTVIt++)
20000  {
20001  for(int AnsLen = 0; AnsLen <= TTVIt->TextString.Length(); AnsLen++)
20002  {
20003  if((TTVIt->TextString).c_str()[AnsLen] != '\0')
20004  {
20005  wss << (TTVIt->TextString).c_str()[AnsLen];
20006  }
20007  else
20008  {
20009  wss << '\n';
20010  }
20011  }
20012  wss << TTVIt->HPos;
20013  wss << '\n';
20014  wss << TTVIt->VPos;
20015  wss << '\n';
20016  for(int AnsLen = 0; AnsLen <= AnsiString(TTVIt->Font->Name).Length(); AnsLen++)
20017  {
20018  if(AnsiString(TTVIt->Font->Name).c_str()[AnsLen] != '\0')
20019  {
20020  wss << AnsiString(TTVIt->Font->Name).c_str()[AnsLen];
20021  }
20022  else
20023  {
20024  wss << '\n';
20025  }
20026  }
20027  wss << TTVIt->Font->Size;
20028  wss << '\n';
20029  if((TTVIt->Font->Color < 0) || (TTVIt->Font->Color > 0xFFFFFF)) // if set to any of the special 'windows' colours save it as black
20030  {
20031  wss << "0\n";
20032  }
20033  else
20034  {
20035  wss << int(TTVIt->Font->Color) << '\n';
20036  }
20037  wss << int(TTVIt->Font->Charset) << '\n'; // save as 'int' (would be unsigned char else) so 'n' can act as proper delimiter
20038  wss << TextHandler->GetFontStyleAsInt(1, TTVIt->Font) << '\n';
20039  }
20040  wss << "$$$" << '\n'; // send text item end marker
20041  wss << SelectBitmap->Height;
20042  wss << '\n';
20043  wss << SelectBitmap->Width;
20044  wss << '\n';
20045  wss << SelectRect.left;
20046  wss << '\n';
20047  wss << SelectRect.top;
20048  wss << '\n';
20049  wss << "$$$" << '\n'; // send final marker
20050  wss << '\0'; // has to end with NULL
20051 
20052  Clipboard()->Clear(); // clear the clipboard
20053  Clipboard()->SetTextBuf(&(wss.str()[0])); // populate the clipboard
20054  Clipboard()->Close();
20055 
20056  Utilities->CallLogPop(2267);
20057  }
20058 
20059  catch(const EClipboardException &e) // ignore access denials (but only seems to happen with recover), doesn't affect program
20060  {
20061 // Application->MessageBox(L"A clipboard error occurred in loading the clipboard", L"Message", MB_OK);
20062  }
20063 
20064  catch(const Exception &e)
20065  {
20066  ErrorLog(222, e.Message);
20067  }
20068 
20069 }
20070 
20071 // ---------------------------------------------------------------------------
20072 
20073 void TInterface::RecoverClipboard(int Caller, bool &ValidResult) // new at v2.8.0
20074 {
20075  try
20076  {
20077  TrainController->LogEvent("RecoverClipboard");
20078  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RecoverClipboard");
20079  ValidResult = false;
20080  System::WideChar *SelectVectorBuffer = new System::WideChar[4000000]; // scope for 130 chars per element & 4k resolution (240 x 135 elements)
20081  int StreamSize = 0;
20082  StreamSize = Clipboard()->GetTextBuf(SelectVectorBuffer, 4000000);
20083  Clipboard()->Clear(); // clear it so can't keep pasting same thing as don't permit this in single app
20084  Clipboard()->Close();
20085  if(StreamSize < 14)
20086  {
20087  Utilities->CallLogPop(2270); // ValidResult == false
20088  return;
20089  }
20090  std::wstringstream wss;
20091  wss << SelectVectorBuffer;
20092  ClpBrdValid = AnsiString(SelectVectorBuffer).SubString(1, 13);
20093  PasteMenuItem->Enabled = false;
20094  delete[]SelectVectorBuffer;
20095 
20096  if((ClpBrdValid != AnsiString("RlyClpBrdCopy")) && (ClpBrdValid != AnsiString("RlyClpBrd_Cut")))
20097  {
20098  Utilities->CallLogPop(2268); // ValidResult == false
20099  return;
20100  }
20101  int MarkerCounter = 0;
20102  ClpBrdValid = "";
20103  wchar_t LineString[100]; // big enough for any TrackVector entry
20104  wss.getline(LineString, 100); // RlyClpBrdCopy or ...Cut - discard it
20105  Track->SelectVector.clear();
20106  while(true) // recover active & inactive track
20107  {
20108  wss.getline(LineString, 100);
20109  if(AnsiString(LineString) == "$$$") // end of track element marker
20110  {
20111  MarkerCounter++;
20112  break;
20113  }
20114  // if not $$$ then it's the SpeedTag number
20115  TTrackElement TE = Track->BuildBasicElementFromSpeedTag(5, AnsiString(LineString).ToInt());
20116  wss.getline(LineString, 100);
20117  TE.ActiveTrackElementName = AnsiString(LineString); // if not "$$$" must be the start of the next element
20118  wss.getline(LineString, 100);
20119  TE.ElementID = AnsiString(LineString);
20120  wss.getline(LineString, 100);
20121  TE.LocationName = AnsiString(LineString);
20122 
20123  wss.getline(LineString, 100);
20124  TE.CallingOnSet = AnsiString(LineString).ToInt();
20125  wss.getline(LineString, 100);
20126  TE.LCPlotted = AnsiString(LineString).ToInt();
20127  wss.getline(LineString, 100);
20128  TE.TempTrackMarker01 = AnsiString(LineString).ToInt();
20129  wss.getline(LineString, 100);
20130  TE.TempTrackMarker23 = AnsiString(LineString).ToInt();
20131 
20132  wss.getline(LineString, 100);
20133  TE.Attribute = AnsiString(LineString).ToInt();
20134  wss.getline(LineString, 100);
20135  TE.Conn[0] = AnsiString(LineString).ToInt();
20136  wss.getline(LineString, 100);
20137  TE.Conn[1] = AnsiString(LineString).ToInt();
20138  wss.getline(LineString, 100);
20139  TE.Conn[2] = AnsiString(LineString).ToInt();
20140  wss.getline(LineString, 100);
20141  TE.Conn[3] = AnsiString(LineString).ToInt();
20142  wss.getline(LineString, 100);
20143  TE.ConnLinkPos[0] = AnsiString(LineString).ToInt();
20144  wss.getline(LineString, 100);
20145  TE.ConnLinkPos[1] = AnsiString(LineString).ToInt();
20146  wss.getline(LineString, 100);
20147  TE.ConnLinkPos[2] = AnsiString(LineString).ToInt();
20148  wss.getline(LineString, 100);
20149  TE.ConnLinkPos[3] = AnsiString(LineString).ToInt();
20150  wss.getline(LineString, 100);
20151  TE.HLoc = AnsiString(LineString).ToInt();
20152  wss.getline(LineString, 100);
20153  TE.VLoc = AnsiString(LineString).ToInt();
20154  wss.getline(LineString, 100);
20155  TE.Length01 = AnsiString(LineString).ToInt();
20156  wss.getline(LineString, 100);
20157  TE.Length23 = AnsiString(LineString).ToInt();
20158  wss.getline(LineString, 100);
20159  TE.SpeedLimit01 = AnsiString(LineString).ToInt();
20160  wss.getline(LineString, 100);
20161  TE.SpeedLimit23 = AnsiString(LineString).ToInt();
20162  wss.getline(LineString, 100);
20163  TE.StationEntryStopLinkPos1 = AnsiString(LineString).ToInt();
20164  wss.getline(LineString, 100);
20165  TE.StationEntryStopLinkPos2 = AnsiString(LineString).ToInt();
20166  wss.getline(LineString, 100);
20167  TE.TrainIDOnElement = AnsiString(LineString).ToInt();
20168  wss.getline(LineString, 100);
20169  TE.TrainIDOnBridgeTrackPos01 = AnsiString(LineString).ToInt();
20170  wss.getline(LineString, 100);
20171  TE.TrainIDOnBridgeTrackPos23 = AnsiString(LineString).ToInt();
20172 
20173  wss.getline(LineString, 100);
20174  int temp = AnsiString(LineString).ToInt();
20175  if(temp == 0)
20176  {
20178  }
20179  else if(temp == 1)
20180  {
20182  }
20183  else if(temp == 2)
20184  {
20186  }
20187  else if(temp == 3)
20188  {
20190  }
20191  Track->SelectVector.push_back(TE);
20192  }
20193 
20194  TextHandler->SelectTextVector.clear();
20195  AnsiString FontName;
20196  int FontSize, FontColour, FontCharset, FontStyle;
20197  while(true) // recover text
20198  {
20199  wss.getline(LineString, 100);
20200  if(AnsiString(LineString) == "$$$") // end of text marker
20201  {
20202  MarkerCounter++;
20203  break;
20204  }
20205  // if not $$$ then it's the text string
20206  TTextItem TI;
20207  TI.TextString = AnsiString(LineString);
20208  wss.getline(LineString, 100);
20209  TI.HPos = AnsiString(LineString).ToInt();
20210  wss.getline(LineString, 100);
20211  TI.VPos = AnsiString(LineString).ToInt();
20212  wss.getline(LineString, 100);
20213  FontName = AnsiString(LineString).c_str();
20214  wss.getline(LineString, 100);
20215  FontSize = AnsiString(LineString).ToInt();
20216  wss.getline(LineString, 100);
20217  FontColour = AnsiString(LineString).ToInt();
20218  wss.getline(LineString, 100);
20219  FontCharset = AnsiString(LineString).ToInt();
20220  wss.getline(LineString, 100);
20221  FontStyle = AnsiString(LineString).ToInt();
20222  // create a new font
20223  TFont *NewFont = new TFont;
20224  NewFont->Name = FontName;
20225  NewFont->Size = FontSize;
20226  NewFont->Color = static_cast<TColor>(FontColour);
20227  NewFont->Charset = FontCharset;
20228  NewFont->Style = TextHandler->SetFontStyleFromInt(1, FontStyle);
20229  TI.Font = NewFont;
20230  TextHandler->SelectTextVector.push_back(TI);
20231  }
20232 
20233  wss.getline(LineString, 100);
20234  SelectBitmap->Height = AnsiString(LineString).ToInt();
20235  wss.getline(LineString, 100);
20236  SelectBitmap->Width = AnsiString(LineString).ToInt();
20237  wss.getline(LineString, 100);
20238  SelectRect.left = AnsiString(LineString).ToInt();
20239  wss.getline(LineString, 100);
20240  SelectRect.top = AnsiString(LineString).ToInt();
20241  wss.getline(LineString, 100);
20242  if(AnsiString(LineString) == "$$$")
20243  {
20244  MarkerCounter++;
20245  }
20246  if(MarkerCounter == 3)
20247  {
20248  ValidResult = true;
20249  }
20250  Utilities->CallLogPop(2269);
20251  }
20252 
20253  catch(const EClipboardException &e) // just reset ValidResult for access denials, doesn't affect program
20254  {
20255 // Application->MessageBox(L"A clipboard error occurred in recovering the clipboard", L"Message", MB_OK);
20256  ValidResult = false;
20257  }
20258 
20259  catch(const Exception &e)
20260  {
20261  ErrorLog(223, e.Message);
20262  }
20263 
20264 }
20265 
20266 // ---------------------------------------------------------------------------
20267 
20268 /*
20269  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
20270 
20271  These problems were with Borland C++Builder 4.
20272 
20273  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
20274  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
20275  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
20276  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
20277  clear what was special about this particular string.
20278  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
20279  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
20280  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
20281  This is thought to be a flaw in the compiler.
20282  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
20283  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
20284  read a null, even though the pointer had been reset to its value before the call to
20285  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
20286  that is indicated by tellg and the true pointer within the system can be different.
20287  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
20288  used for both with the new library just defined within the std namespace.
20289  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
20290  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
20291  (note - don't need the ifstream file to be open in output mode for the putback to work)
20292  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
20293  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
20294  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
20295  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
20296  file and that read by the program.
20297  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
20298  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
20299  'Frh' at the end of the entry following that for the earlier sticking point. Here
20300  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
20301  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
20302  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
20303  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
20304  would tally, though would still be wrong.
20305  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
20306  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
20307  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
20308  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
20309  lines are only separated by single newline characters.
20310 
20311  Need to check:
20312  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
20313  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
20314  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
20315 
20316  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
20317  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
20318  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
20319  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
20320 
20321  For 2: Works OK using getline().
20322 
20323  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
20324  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
20325  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
20326  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
20327 
20328  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
20329 */
20330 
20331 // ---------------------------------------------------------------------------
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17224
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:563
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3795
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:948
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:481
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11157
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8876
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:417
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:347
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1117
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:855
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:314
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:644
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:313
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11130
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:116
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:467
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:278
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:92
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2751
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:646
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:443
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:538
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1039
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12992
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:205
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:18138
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:546
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1093
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:359
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:305
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12676
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12806
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:855
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1599
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:201
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:340
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12387
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:105
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:647
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:462
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:335
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:18351
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:754
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:465
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:716
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:94
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:51
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:466
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4354
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:12659
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:574
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:648
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:536
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4265
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1091
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:202
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:268
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:50
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1079
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:558
TInterface::PasteWarningSentFlag
bool PasteWarningSentFlag
indicates that the warning message about pasting overwriting the area has been given,...
Definition: InterfaceUnit.h:972
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1103
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:312
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:353
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:197
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:717
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1049
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12716
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3162
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1045
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10193
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3620
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:868
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:1024
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:1004
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:18925
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2081
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:264
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:393
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:341
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:700
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:297
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1052
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7034
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:51
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:657
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:929
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1528
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:523
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5530
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6935
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5557
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:119
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:8165
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:684
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:285
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:571
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:432
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:624
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1065
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:427
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1909
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:339
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10057
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:16933
TInterface::ClpBrdValid
AnsiString ClpBrdValid
set to RlyClpBrdCopy or RlyClpBrd_Cut when Windows Clipboard contains a valid railway segment
Definition: InterfaceUnit.h:905
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:397
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:556
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:870
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:998
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:489
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11756
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:533
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2733
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:620
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5686
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:153
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:335
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1077
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:887
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:72
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7897
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:429
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:379
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:571
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:19620
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:1006
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:347
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:308
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:740
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:229
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12455
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:275
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:355
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:1022
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7364
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:146
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9121
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:594
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:335
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:731
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:740
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1765
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9372
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:639
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:615
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:984
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:297
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:11909
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13597
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14832
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:19763
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:7412
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:348
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:137
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:512
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1119
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:128
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17184
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:376
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18020
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:990
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:142
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2100
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:425
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:15110
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:740
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:17403
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:506
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:8292
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:936
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:18798
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:463
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:160
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:100
TInterface::SigPrefConsecButtonClick
void __fastcall SigPrefConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2165
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3571
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4355
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:877
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:14847
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:545
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:444
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1050
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:877
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3318
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10294
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:855
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9060
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3495
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:450
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:19779
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:242
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:397
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1097
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1401
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:551
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11668
NotStarted
@ NotStarted
Definition: TrainUnit.h:86
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4515
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:763
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2244
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:415
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6218
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1043
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1048
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12954
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:889
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:782
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3447
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:245
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11053
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:787
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:132
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:643
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:507
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:315
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:14792
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:64
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:343
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:184
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:780
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18493
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5630
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:533
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:539
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8998
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:18688
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9268
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:183
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2062
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:18938
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:6243
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:113
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:446
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1421
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1507
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5694
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:468
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:600
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12406
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:294
TTextHandler::GetFontStyleAsInt
int GetFontStyleAsInt(int Caller, TFont *InputFont)
retrieve the style of the font as a coded integer
Definition: TextUnit.cpp:99
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1336
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TInterface::SetTrackModeEditMenu
void SetTrackModeEditMenu(int Caller)
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:19500
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:676
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2659
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:529
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:456
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:970
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:14950
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3171
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:276
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15183
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4836
TInterface::ClipboardChecked
bool ClipboardChecked
used to prevent Windows clipboard beng checked repeatedly
Definition: InterfaceUnit.h:940
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:15809
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:13579
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:13416
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1159
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:14888
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:630
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:50
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12521
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:704
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:316
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:438
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2782
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12971
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10493
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1054
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4765
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1041
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:876
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:942
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12771
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5646
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:463
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1600
TTrain
Definition: TrainUnit.h:279
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:296
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:10552
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11171
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:262
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1088
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:94
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:552
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:986
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:810
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7379
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:577
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:342
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:440
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1047
GapJump
@ GapJump
Definition: TrackUnit.h:67
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:282
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:119
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:566
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:562
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:782
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:927
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:855
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:464
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7181
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:521
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12266
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::IsReadyForOperation
bool IsReadyForOperation(bool GiveMessage)
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:737
TTrack::Raising
@ Raising
Definition: TrackUnit.h:533
TInterface::OAListBoxRightMouseButtonDown
bool OAListBoxRightMouseButtonDown
flag set when right mouse button clicked over op action list box, so floating information window show...
Definition: InterfaceUnit.h:970
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:8970
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:584
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10162
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:335
TTrackElement::TempTrackMarker23
bool TempTrackMarker23
Utility markers for program use.
Definition: TrackUnit.h:141
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:509
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1176
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:491
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1567
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11736
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:335
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:18906
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:913
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4793
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:198
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:530
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:253
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1081
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:329
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:202
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:649
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:254
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:16746
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:579
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:14929
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:952
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:777
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:298
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:357
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:422
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:888
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:638
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:439
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1287
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:576
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:144
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5878
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1427
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9470
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:200
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:871
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:13330
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:365
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6824
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:544
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:310
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:559
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:385
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:129
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:543
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:15167
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:19652
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:10270
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:366
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12738
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:303
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:792
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:15012
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5554
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:887
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:393
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:121
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:712
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:127
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:378
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:581
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3738
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:989
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:990
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:768
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:786
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:67
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:186
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:893
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:387
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9233
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:426
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17172
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:431
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:372
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1820
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11155
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:135
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:17971
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1056
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3965
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7393
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6627
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1123
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1101
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:597
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:623
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:931
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8557
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:315
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12235
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:866
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:11596
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17157
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:266
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:63
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:390
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11726
TInterface::LoadClipboard
void LoadClipboard(int Caller)
Load system clipboard to allow cutting & pasting between separate railway applications.
Definition: InterfaceUnit.cpp:19890
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:788
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:279
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:382
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1045
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:721
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2589
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1930
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:385
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1121
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10774
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:431
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13238
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:13366
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:882
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:436
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1047
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:785
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:411
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1093
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:754
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4440
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:255
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1859
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:395
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:580
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:440
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:649
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:882
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:592
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:783
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4480
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:399
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1057
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:532
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1587
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:180
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:194
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10589
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:686
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:113
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:440
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:1000
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:416
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:445
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:567
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:625
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:9870
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2642
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:640
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1136
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:274
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:335
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:994
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:160
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:380
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1878
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:374
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:740
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:888
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:366
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:447
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1380
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:541
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:855
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11930
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:10989
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:435
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1147
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:770
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:299
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:505
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:818
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:19393
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5893
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1433
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10679
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:887
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8354
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:743
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1615
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1059
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1591
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:16955
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1593
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:514
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:292
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:607
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:768
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:766
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5817
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:1002
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11995
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:589
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10062
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7785
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:19146
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1597
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9607
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:198
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1083
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:609
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:587
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6680
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:757
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12488
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1729
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:962
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:635
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9491
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:448
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:934
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3548
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:68
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:605
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:428
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2438
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11032
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:70
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1090
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4818
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2339
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1761
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12483
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:600
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12311
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1086
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:549
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12084
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:925
TInterface::FillSelectionMessageSentFlag
bool FillSelectionMessageSentFlag
indicates that the message about filling a selected area with a chosen track element has been given,...
Definition: InterfaceUnit.h:958
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1957
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:363
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:833
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:645
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:1016
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:777
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:628
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:399
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12308
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:522
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:354
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:426
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:52
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:721
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:548
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:335
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:138
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:764
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3712
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:356
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10368
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:627
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:90
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:646
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:199
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:137
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:349
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4328
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:561
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1058
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:489
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5605
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1795
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12330
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13176
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:240
TInterface::LCManualLowerBarriersMessageSent
bool LCManualLowerBarriersMessageSent
indicates that the manual LC operation message has been given, so it won't be given again
Definition: InterfaceUnit.h:960
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2848
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:141
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:52
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:787
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:554
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:564
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5671
TInterface::RecoverClipboard
void RecoverClipboard(int Caller, bool &ValidResult)
Recovers clipboard as track and text vectors.
Definition: InterfaceUnit.cpp:20073
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3764
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
new v2.2.0, incremented in Interface.cpp, controls updating for OpTimeToActPanel
Definition: TrainUnit.h:802
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:349
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5184
TInterface::CopySelected
bool CopySelected
used to indicate whether copy or cut selected in edit menu - for clipboard pasting
Definition: InterfaceUnit.h:946
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1142
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:11064
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:18719
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13009
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11697
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:887
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:13608
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9314
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:295
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:496
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:888
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:769
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:323
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1090
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4912
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:15165
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:612
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1383
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8321
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:18774
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1538
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:440
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17011
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1527
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:341
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:350
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:200
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:196
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:775
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:140
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:590
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:626
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6085
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:608
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:477
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1046
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7090
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9696
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:475
AtLocation
@ AtLocation
Definition: TrainUnit.h:70
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:148
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:77
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:1010
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:17764
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:693
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17461
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:155
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:459
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:816
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12358
TAllRoutes::NotAutoSigsRoute
@ NotAutoSigsRoute
Definition: TrackUnit.h:1528
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:422
Exited
@ Exited
Definition: TrainUnit.h:86
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:293
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:230
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:578
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8937
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:384
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10817
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:16607
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:554
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:10257
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:14863
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:535
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:1008
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2290
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:595
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1099
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:617
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:586
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:569
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:636
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:698
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:15974
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:250
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:440
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:700
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12368
TInterface::OAListBoxMouseDown
void __fastcall OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4969
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:420
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:454
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:742
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:19613
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:404
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8845
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:495
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2034
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:4065
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1595
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:1018
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:370
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:520
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4418
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:181
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:754
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12543
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:321
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:547
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14006
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:335
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:16857
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4043
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:887
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2340
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:790
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10232
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12151
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12126
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:292
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:363
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:588
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:581
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:632
TInterface::GetTrainFloatingInfoFromContinuation
void GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
Called when floating train info needed and train hasn't entered yet.
Definition: InterfaceUnit.cpp:15608
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:860
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5581
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:175
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18661
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:218
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:101
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10530
TTrack::Down
@ Down
Definition: TrackUnit.h:533
TTrainController::TwoOrMoreLocationsWarningGiven
bool TwoOrMoreLocationsWarningGiven
new at v2.6.0 to allow loops
Definition: TrainUnit.h:750
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:311
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:583
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:112
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:555
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:16689
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:64
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1414
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:1014
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6788
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:870
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:596
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10081
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:440
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:233
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:504
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:204
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12018
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17103
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7163
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:14912
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11787
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:406
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:18743
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:82
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:519
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
Timetable
@ Timetable
Definition: TrainUnit.h:58
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TInterface
Definition: InterfaceUnit.h:56
TTextHandler::SetFontStyleFromInt
TFontStyles SetFontStyleFromInt(int Caller, int Input)
used in loading from a file
Definition: TextUnit.cpp:126
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10864
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9686
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6735
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:748
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:17342
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:540
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5742
Parapet
@ Parapet
Definition: TrackUnit.h:68
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:684
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17130
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1056
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:508
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:740
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:285
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8838
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17076
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:521
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:401
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:746
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:721
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:754
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:696
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:440
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:548
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:249
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:454
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:406
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:338
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:145
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:370
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:567
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:523
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1136
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:557
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:611
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:15188
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9342
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:139
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12053
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:419
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:616
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12874
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1159
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:499
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11716
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1055
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:791
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:911
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11766
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1138
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:732
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:510
TTrack
Definition: TrackUnit.h:473
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5835
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:768
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:424
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:73
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:389
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:482
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1061
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:978
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:460
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:888
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:66
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:410
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:263
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
new at v2.4.0, resets after 53 seconds (53 prime so can trigger at any clock time)
Definition: TrainUnit.h:806
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:627
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:872
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:966
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:619
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:858
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:219
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:280
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1125
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:69
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:565
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:549
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:130
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1145
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:585
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:280
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:853
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2885
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:13093
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5508
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:421
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5600
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8682
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1136
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4579
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4194
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:747
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:383
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:839
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1601
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:511
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:754
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:361
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2092
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3366
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:414
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:573
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11707
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:257
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:528
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:1020
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1156
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5856
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:422
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:160
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:704
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1067
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2558
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:111
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:52
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:900
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:189
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:437
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:190
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11841
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:909
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12619
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2312
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:15034
IDInt
Definition: TrackUnit.h:422
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10100
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1075
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:19849
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1159
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:85
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:297
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4328
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3214
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4661
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:513
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12444
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9944
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:808
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1109
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:182
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:553
TInterface::SigPrefNonConsecButton
TBitBtn * SigPrefNonConsecButton
Definition: InterfaceUnit.h:654
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:441
TInterface::GetTrainStatusFloat
AnsiString GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
used for floating window to display train status
Definition: InterfaceUnit.cpp:15702
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:190
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:277
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:319
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1162
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:9388
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:51
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:373
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:494
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:213
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5717
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:99
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:8696
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:886
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:404
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:682
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:13802
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1589
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1582
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:16257
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:867
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:132
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:453
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2398
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7444
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11655
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1035
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:204
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11746
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:554
TInterface::RecoverClipboardMessageSent
bool RecoverClipboardMessageSent
indicates that the warning about pasting at top left in a new application has been given,...
Definition: InterfaceUnit.h:980
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:803
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1400
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:584
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4951
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:15048
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:923
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11810
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:618
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:888
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:77
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3140
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1033
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:117
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:88
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:372
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:637
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1293
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:655
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:653
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:9040
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:522
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:988
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:917
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:878
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:944
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:14989
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:593
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:776
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1172
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:15201
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:13071
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:671
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13104
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11997
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1199
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:550
Points
@ Points
Definition: TrackUnit.h:67
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:771
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:13562
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:13483
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:359
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:804
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:754
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:298
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:789
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1073
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:52
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3357
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1115
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12896
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1162
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1831
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12600
TInterface::SigPrefNonConsecButtonClick
void __fastcall SigPrefNonConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2205
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1053
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:367
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:458
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16405
Continuation
@ Continuation
Definition: TrackUnit.h:67
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:251
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:143
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:740
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:71
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:802
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3648
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5817
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1074
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9390
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:598
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1044
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4044
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:313
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:669
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:784
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:432
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:544
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:9742
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:331
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:261
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11884
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:17823
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12708
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:179
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:488
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:433
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1623
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:52
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:877
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:954
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1032
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1132
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:303
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11862
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:19225
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11888
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:9419
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3265
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:377
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1417
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:438
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:343
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9271
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1130
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:345
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11802
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:622
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:540
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1159
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:8228
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:560
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:499
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3608
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3126
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:844
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:921
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:195
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:485
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:964
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:279
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:887
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:1012
TInterface::CancelSelectionFlag
bool CancelSelectionFlag
used in case pasting to avoid RecoverClipboard call when set
Definition: InterfaceUnit.h:938
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:461
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:352
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:974
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:5282
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11678
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:610
TTrackElement::TempTrackMarker01
bool TempTrackMarker01
Definition: TrackUnit.h:141
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:17817
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:688
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:629
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:525
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:797
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4581
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:568
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4860
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1609
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8368
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:69
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:708
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3526
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:688
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4542
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:899
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:3066
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1159
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:628
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:212
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:18038
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:236
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:5033
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:907
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:516
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18645
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:430
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1034
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1841
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4566
Connection
@ Connection
Definition: TrackUnit.h:77
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4700
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3625
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:740
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1584
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:80
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:295
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3567
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:82
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16218
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1111
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:17918
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:133
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12929
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12523
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:142
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:570
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6861
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4361
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1121
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:602
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:103
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:413
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:599
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1157
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5625
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:412
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:887
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:302
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:124
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:252
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:335
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:675
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:779
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:117
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1052
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:9010
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:103
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1071
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:387
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:6999
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:655
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13026
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17144
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12503
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1058
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:381
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7404
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3027
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:9025
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:534
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:134
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:329
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:768
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:650
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:814
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:550
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:968
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:334
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:820
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:919
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1153
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:311
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:173
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1042
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:673
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:203
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:8368
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:344
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:601
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:14994
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:265
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:517
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:300
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:16713
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:531
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1299
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:19587
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7544
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:887
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:575
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1036
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:281
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:99
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:613
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:244
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3906
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:604
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:19697
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1046
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11262
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:357
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:13519
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:569
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1038
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:781
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:59
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:440
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:483
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:102
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:476
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12425
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:754
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1113
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:64
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:214
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:409
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:799
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:774
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11687
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:106
TTrainController::TTEditPanelVisible
bool TTEditPanelVisible
new at v2.6.0 so potential error message only shows in TTEdit mode
Definition: TrainUnit.h:752
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:5035
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:526
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:335
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:440
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:634
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:772
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:78
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1049
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10132
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4183
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:283
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:714
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4457
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:887
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1936
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:416
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:725
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:451
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9358
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1051
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1105
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:19795
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1112
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:17698
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:575
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7118
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:410
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2003
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1281
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:982
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:855
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:976
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:679
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1117
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4482
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:651
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:188
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:690
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:633
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:478
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:474
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1040
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:98
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1206
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12349
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:14868
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9207
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:147
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:377
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1746
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:19630
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:270
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15410
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:103
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:642
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:716
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:118
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:621
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:369
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:543
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:827
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:171
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1974
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:996
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:754
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:537
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6142
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3628
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:51
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3525
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1899
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1860
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:14144
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:18197
TInterface::None
@ None
Definition: InterfaceUnit.h:893
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:591
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:11081
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:75
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10731
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:661
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1031
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:246
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:631
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:768
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:812
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1095
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:399
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:659
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:546
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1105
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:677
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:778
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:992
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1037
TTextItem::TextString
AnsiString TextString
the text string
Definition: TextUnit.h:46
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:65
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:527
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:923
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:154
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:524
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:17466
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:877
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:641
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:125
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3408
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:107
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1083
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11196
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:582
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1060
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:186
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:187
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5330
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6766
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:441
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:309
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:572
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:17076
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18190
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1136
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1053
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10740
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:882
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:490
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1069
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10760
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:134
TInterface::SigPrefConsecButton
TBitBtn * SigPrefConsecButton
Definition: InterfaceUnit.h:196
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:436
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:537
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12463
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:596
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:532
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:754
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:434
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6043
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:160
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:18214
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:480
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:441
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9874
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:518
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:76
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:653
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:614
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:301
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:869
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1037
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:956
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3833
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2125
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1054
Signaller
@ Signaller
Definition: TrainUnit.h:58
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:527
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2938
TRailGraphics::smYellow
Graphics::TBitmap * smYellow
Definition: GraphicUnit.h:887
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1150
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:622
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10017
Bridge
@ Bridge
Definition: TrackUnit.h:67
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:950
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9449
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:542
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:13506
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:606
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:391
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:603
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:243
Buffers
@ Buffers
Definition: TrackUnit.h:67
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:887
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:209
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:749
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11220
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4733
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9547
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:515
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:893
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4394
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:452
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:552
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11836
TInterface::GetTrainIDOrContinuationPosition
bool GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &ContinuationPos)
Used in actions due panel to identify the train or continuation.
Definition: InterfaceUnit.cpp:4989